Split the modularity patch into smaller pieces. Add the yangui module
[dlux.git] / src / common / yangutils / yangutils.services.js
1 define(['common/yangutils/yangutils.module'], function(yangUtils) {\r
2 \r
3   // In the yangui.module.js, this file is loader immediatly after\r
4   // his module. So we don't need to register the services.\r
5 \r
6   yangUtils.factory('reqBuilder', function () {\r
7 \r
8       var namespace = 'flow-node-inventory';\r
9 \r
10       var builder = {\r
11           namespace: namespace,\r
12           createObj: function() {\r
13               return {};\r
14           },\r
15 \r
16           createList: function() {\r
17               return [];\r
18           },\r
19 \r
20           insertObjToList: function(list, obj) {\r
21               list.push(obj);\r
22           },\r
23 \r
24           insertPropertyToObj: function(obj, propName, propData) {\r
25               var data = propData ? propData : {},\r
26                   name = propName;\r
27 \r
28               obj[name] = data;\r
29           },\r
30 \r
31           resultToString: function(obj) {\r
32               return JSON.stringify(obj, null, 4);\r
33           }\r
34       };\r
35 \r
36       return builder;\r
37 \r
38   });\r
39 \r
40   yangUtils.factory('nodeWrapper', function () {\r
41 \r
42       var comparePropToElemByName = function comparePropToElemByName(propName, elemName) {\r
43           return propName.split(':')[1] === elemName; //TODO modify when namespace relations will be known\r
44       };\r
45 \r
46       var wrapper = {\r
47 \r
48           wrap: function(node) {\r
49               if(this.hasOwnProperty(node.type)) {\r
50                   this[node.type](node);\r
51               }\r
52           },\r
53 \r
54           wrapAll: function(node) {\r
55               var self = this;\r
56               self.wrap(node);\r
57               node.children.forEach(function(child) {\r
58                   self.wrapAll(child);\r
59               });\r
60           },\r
61 \r
62           leaf: function(node) {\r
63               node.value = '';\r
64 \r
65               node.buildRequest = function(builder, req) {\r
66                   if(node.value) {\r
67                       builder.insertPropertyToObj(req, node.label, node.value);\r
68                       return true;\r
69                   }\r
70 \r
71                   return false;\r
72               };\r
73 \r
74               node.fill = function(name, data) {\r
75                   var match = comparePropToElemByName(name, node.label);\r
76 \r
77                   if(match) {\r
78                       node.value = data;\r
79                   }\r
80 \r
81                   return match;\r
82               };\r
83 \r
84               node.clear = function() {\r
85                   node.value = '';\r
86               };\r
87           },\r
88 \r
89           container: function(node) {\r
90               node.expanded = false;\r
91 \r
92               node.toggleExpand = function() {\r
93                   node.expanded = !node.expanded;\r
94               };\r
95 \r
96               node.buildRequest = function(builder, req) {\r
97                   var added = false,\r
98                       name = node.label,\r
99                       objToAdd = builder.createObj();\r
100 \r
101                   if(node.children.length) {\r
102                       node.children.forEach(function(child) {\r
103                           var childAdded = child.buildRequest(builder, objToAdd);\r
104                           added = added || childAdded;\r
105                       });\r
106                   } else {\r
107                       added = true;\r
108                   }\r
109 \r
110                   if(added) {\r
111                       builder.insertPropertyToObj(req, name, objToAdd);\r
112                   }\r
113 \r
114                   return added;\r
115               };\r
116 \r
117               node.fill = function(name, data) {\r
118                   var match = comparePropToElemByName(name, node.label);\r
119 \r
120                   if (match && node.children.length) {\r
121                       node.children.forEach(function(child) {\r
122                           for(var prop in data) {\r
123                               child.fill(prop, data[prop]);\r
124                           }\r
125                       });\r
126 \r
127                       node.expanded = true;\r
128                   }\r
129                   return match;\r
130               };\r
131 \r
132               node.clear = function() {\r
133                   if (node.children.length) {\r
134                       node.children.forEach(function(child) {\r
135                           child.clear();\r
136                       });\r
137                   }\r
138               };\r
139 \r
140           },\r
141 \r
142           case: function(node) {\r
143               node.buildRequest = function(builder, req) {\r
144                   var added = false;\r
145 \r
146                   node.children.forEach(function(child) {\r
147                       var childAdded = child.buildRequest(builder, req);\r
148                       added = added || childAdded;\r
149                   });\r
150 \r
151                   return added;\r
152               };\r
153 \r
154               node.fill = function(name, data) {\r
155                   var filled = false;\r
156 \r
157                   node.children.forEach(function(child) {\r
158                       var childFilled = child.fill(name, data);\r
159                       filled = filled || childFilled;\r
160                   });\r
161 \r
162                   return filled;\r
163               };\r
164 \r
165               node.clear = function() {\r
166                   node.children.forEach(function(child) {\r
167                       child.clear();\r
168                   });\r
169               };\r
170           },\r
171 \r
172           choice: function(node) {\r
173               node.choice = null;\r
174               node.buildRequest = function(builder, req) {\r
175                   var added;\r
176 \r
177                   if(node.choice) {\r
178                       added = node.choice.buildRequest(builder, req);\r
179                   }\r
180 \r
181                   return added;\r
182               };\r
183 \r
184               node.fill = function(name, data) {\r
185                   var filled = false;\r
186 \r
187                   node.children.forEach(function(child) {\r
188                       var childFilled = child.fill(name, data);\r
189 \r
190                       if(childFilled) {\r
191                           node.choice = child;\r
192                       }\r
193 \r
194                       filled = filled || childFilled;\r
195                       if(filled) {\r
196                           return false;\r
197                       }\r
198                   });\r
199 \r
200                   return filled;\r
201               };\r
202 \r
203               node.clear = function() {\r
204                   if(node.choice) {\r
205                       node.choice.clear();\r
206                       node.choice = null;\r
207                   }\r
208               };\r
209           },\r
210 \r
211           list: function(node) {\r
212 \r
213               node.listElems = [];\r
214               node.actElement = null;\r
215               node.needAddNewListElem = true;\r
216 \r
217               node.addListElem = function() {\r
218                   var copy = node.deepCopy();\r
219                   wrapper.wrapAll(copy);\r
220                   node.listElems.push(copy);\r
221                   node.needAddNewListElem = false;\r
222                   node.actElement = node.listElems[node.listElems.length - 1];\r
223               };\r
224 \r
225               node.removeListElem = function(elem) {\r
226                   node.listElems.splice(node.listElems.indexOf(elem), 1);\r
227                   if(node.listElems.length) {\r
228                       node.actElement = node.listElems[node.listElems.length - 1];\r
229                   } else {\r
230                       node.actElement = null;\r
231                   }\r
232               };\r
233 \r
234               var listElemBuildRequest = function(builder, req, node) {\r
235                   var added = false,\r
236                       objToAdd = builder.createObj();\r
237 \r
238                   node.children.forEach(function(child) {\r
239                       var childAdded = child.buildRequest(builder, objToAdd);\r
240                       added = added || childAdded;\r
241                   });\r
242 \r
243                   if(added) {\r
244                       builder.insertObjToList(req, objToAdd);\r
245                   }\r
246 \r
247                   return added;\r
248               };\r
249 \r
250               var fillListElement = function(name, data, node) {\r
251                   var filled = false;\r
252 \r
253                   node.children.forEach(function(child) {\r
254                       var childFilled = child.fill(name, data);\r
255                       filled = filled || childFilled;\r
256                   });\r
257 \r
258                   return filled;\r
259               };\r
260 \r
261               node.buildRequest = function(builder, req) {\r
262                   var added = false,\r
263                       listToAdd = builder.createList();\r
264 \r
265                   node.listElems.forEach(function(listElem) {\r
266                       var elemAdded = listElemBuildRequest(builder, listToAdd, listElem);\r
267                       added = added || elemAdded;\r
268                   });\r
269 \r
270                   if(added) {\r
271                       builder.insertPropertyToObj(req, node.label, listToAdd);\r
272                   }\r
273 \r
274                   return added;\r
275               };\r
276 \r
277               node.fill = function(name, array) { //data is array\r
278                   var match = comparePropToElemByName(name, node.label),\r
279                       lastIndex;\r
280 \r
281                   if(match) {\r
282                       for(var i in array) {\r
283                           node.addListElem();\r
284 \r
285                           lastIndex = node.listElems.length - 1;\r
286                           for(var prop in array[i]) {\r
287                               node.needAddNewListElem = fillListElement( prop, array[i][prop], node.listElems[lastIndex]);\r
288                           }\r
289                       }\r
290                   }\r
291                   return match;\r
292               };\r
293 \r
294               node.clear = function() {\r
295                   while(node.listElems.length > 0) {\r
296                       node.listElems.pop();\r
297                   }\r
298                   node.needAddNewListElem = true;\r
299               };\r
300           }\r
301       };\r
302 \r
303       return wrapper;\r
304   });\r
305 \r
306   yangUtils.factory('yinParser', function ($http, $timeout) {\r
307 \r
308       var path = './assets';\r
309       var runningRequests = [];\r
310       var reqId = 0;\r
311 \r
312       var spawnRequest = function(digest) {\r
313           var id = digest+(reqId++).toString();\r
314           runningRequests.push(id);\r
315           // console.debug('adding request '+id+' total running requests  = '+runningRequests.length);\r
316           return id;\r
317       };\r
318 \r
319       var removeRequest = function(id) {\r
320           var index = runningRequests.indexOf(id);\r
321 \r
322           if (index > -1) {\r
323               runningRequests.splice(index, 1);\r
324               // console.debug('removing request '+id+' remaining requests = '+runningRequests.length);\r
325           }\r
326       };\r
327 \r
328       var waitFor = function waitFor(callback) {\r
329           var t = 10,\r
330               processes = runningRequests.length;\r
331 \r
332           // console.debug('waiting for '+t+ 'ms, for '+processes+', processes: '+(processes > 0));\r
333 \r
334           if(processes > 0) {\r
335               $timeout(function() {\r
336                   waitFor(callback);\r
337               }, t);\r
338           } else {\r
339               callback();\r
340           }\r
341       };\r
342 \r
343       var Node = function(id, name, type, module) {\r
344           this.id = id;\r
345           this.label = name;\r
346           this.localeLabel = 'YANGUI_'+name.toUpperCase();\r
347           this.type = type;\r
348           this.module = module;\r
349           this.children = [];\r
350 \r
351           this.deepCopy = function deepCopy() {\r
352               var copy = new Node(this.id, this.label, this.type, this.module);\r
353               this.children.forEach(function(child) {\r
354                   copy.children.push(child.deepCopy());\r
355               });\r
356               return copy;\r
357           };\r
358 \r
359       };\r
360 \r
361       var parentTag = function(xml){\r
362           if (xml.get(0).tagName.toLowerCase() === 'module') {\r
363               return xml.get(0);\r
364           } else {\r
365               return parentTag(xml.parent());\r
366           }\r
367       };\r
368 \r
369       var parseYang = function parseYang(yinPath, callback) {\r
370           var result = null;\r
371 \r
372           runningRequests = [];\r
373           reqId = 0;\r
374 \r
375           $http.get(path+yinPath).success(function (data) {\r
376               var rootModule = $($.parseXML(data).documentElement).attr('name');\r
377 \r
378               yangParser.reset();\r
379               yangParser.setCurrentModule(rootModule);\r
380               yangParser.parse(data, null);\r
381 \r
382               result = yangParser.rootNode;\r
383 \r
384               waitFor(function() {\r
385                   callback(result);\r
386               });\r
387           }).error(function () {\r
388               console.warn('can\'t find module: '+yinPath);\r
389               return null;\r
390           });\r
391       };\r
392 \r
393       var yangParser = {\r
394           currentModule: null,\r
395           rootNode: null,\r
396           nodeIndex: 0,\r
397 \r
398           reset: function() {\r
399               this.rootNode = null;\r
400               this.nodeIndex = 0;\r
401               this.currentModule = null;\r
402           },\r
403           setCurrentModule: function(module) {\r
404               this.currentModule = module;\r
405           },\r
406           createNewNode: function(name, type, parentNode) {\r
407               var node = new Node(this.nodeIndex++, name, type, this.currentModule);\r
408 \r
409               if(this.nodeIndex===1) {\r
410                   this.rootNode = node;\r
411               }\r
412 \r
413               if(parentNode) {\r
414                   parentNode.children.push(node);\r
415               }\r
416 \r
417               return node;\r
418           },\r
419 \r
420           parse: function(xml, parent) {\r
421               var self = this;\r
422 \r
423               $(xml).children().each(function() {\r
424                   var prop = this.tagName.toLowerCase();\r
425 \r
426                   if(self.hasOwnProperty(prop)) {\r
427                       self[prop](this, parent);\r
428                   } else {\r
429                       //self.parse(this, parent);\r
430                   }\r
431               });\r
432           },\r
433 \r
434           leaf: function(xml, parent) {\r
435               var type = 'leaf',\r
436                   name = $(xml).attr('name');\r
437 \r
438               this.createNewNode(name, type, parent);\r
439           },\r
440 \r
441           container: function(xml, parent) {\r
442               var type = 'container',\r
443                   name = $(xml).attr('name');\r
444 \r
445               if($(xml).children().length === 0) { //if empty add as element\r
446                   this.createNewNode(name, type, parent);\r
447               }\r
448               else {\r
449                   var node = this.createNewNode(name, type, parent);\r
450                   this.parse(xml, node);\r
451               }\r
452           },\r
453 \r
454           choice: function(xml, parent) {\r
455               var type = 'choice',\r
456                   name = $(xml).attr('name'),\r
457                   self = this,\r
458                   node = this.createNewNode(name, type, parent);\r
459 \r
460               $(xml).children('case').each(function() {\r
461                   self._case(this, node);\r
462               });\r
463           },\r
464 \r
465           _case: function(xml, parent) {\r
466               var type = 'case',\r
467                   name = $(xml).attr('name'),\r
468                   node = this.createNewNode(name, type, parent);\r
469 \r
470               this.parse(xml, node);\r
471           },\r
472 \r
473           list: function(xml, parent) {\r
474               var type = 'list',\r
475                   name = $(xml).attr('name'),\r
476                   node = this.createNewNode(name, type, parent);\r
477 \r
478               this.parse(xml, node);\r
479           },\r
480 \r
481           _grouping: function(xml, parent, groupingName) {\r
482               var self = this;\r
483 \r
484               $(xml).children('grouping[name=\''+groupingName+'\']').each(function() {\r
485                   self.parse(this, parent);\r
486               });\r
487           },\r
488 \r
489           uses: function(xml, parent) {\r
490               var self = this,\r
491                   $xml = $(xml),\r
492                   name = $xml.attr('name'),\r
493                   names = name.split(':');\r
494 \r
495               if (names[1] === undefined) { //same module\r
496                   self._grouping(parentTag($xml), parent, names[0]);\r
497               }\r
498               else { //different module\r
499                   $(parentTag($xml)).children('import').each(function() {\r
500                       var importTag = $(this);\r
501 \r
502                       importTag.children('prefix[value=\''+names[0]+'\']').each(function() {\r
503                           var importTagModule = importTag.attr('module'),\r
504                               reqId = spawnRequest(importTagModule);\r
505 \r
506                           $http.get(path+'/yang2xml/'+importTagModule+'.yang.xml').success(function (data) {\r
507                               self.setCurrentModule(importTagModule);\r
508                               self._grouping($.parseXML(data).documentElement, parent, names[1]);\r
509                               removeRequest(reqId);\r
510                           });\r
511                       });\r
512                   });\r
513               }\r
514           }\r
515       };\r
516 \r
517       return {\r
518           parse: parseYang\r
519       };\r
520   });\r
521 \r
522   yangUtils.factory('yangUtils', function ($http, yinParser, nodeWrapper, reqBuilder) {\r
523 \r
524       var utils = {};\r
525 \r
526       utils.exportModulesLocales = function(modules) {\r
527           var obj = {},\r
528               localeNodes = ['leaf','list','container','choice'];\r
529 \r
530           var process = function process(node) {\r
531               if(localeNodes.indexOf(node.type) >= 0 && obj.hasOwnProperty(node.localeLabel) === false) {\r
532                   obj[node.localeLabel] = node.label;\r
533               }\r
534 \r
535               node.children.forEach(function(child) {\r
536                   process(child);\r
537               });\r
538           };\r
539 \r
540           modules.forEach(function(module) {\r
541               process(module);\r
542           });\r
543 \r
544           return JSON.stringify(obj, null, 4);\r
545       };\r
546 \r
547       utils.processModules = function(loadedModules, callback) {\r
548           // console.info('loaded modules', loadedModules);\r
549           loadedModules.module.forEach(function(module) {\r
550               yinParser.parse('/yang2xml/'+module.name+'.yang.xml', function(node) {\r
551                   if(node) {\r
552                       var copy = node.deepCopy();\r
553 \r
554                       nodeWrapper.wrapAll(copy);\r
555                       callback(copy);\r
556                   }\r
557               });\r
558           });\r
559       };\r
560 \r
561       utils.buildRequest = function(node) {\r
562           var request = reqBuilder.createObj();\r
563           node.buildRequest(reqBuilder, request);\r
564           return request.flows; //TODO use REST API explorer when it will be available\r
565       };\r
566 \r
567       utils.getRequestString = function(node) {\r
568           var request = reqBuilder.createObj(),\r
569               reqStr = '';\r
570 \r
571           node.buildRequest(reqBuilder, request);\r
572 \r
573           if(request && $.isEmptyObject(request) === false) {\r
574               reqStr = reqBuilder.resultToString(request);\r
575           }\r
576           return reqStr;\r
577       };\r
578 \r
579       utils.processNodes = function(invData) {\r
580           var nodes =[];\r
581 \r
582           invData.node.forEach(function(node) {\r
583               nodes.push(node.id);\r
584           });\r
585           return nodes;\r
586       };\r
587 \r
588       utils.processFlows = function(nodeData) {\r
589           var flows = [];\r
590 \r
591           nodeData['flow-node-inventory:table'].forEach(function(table) {\r
592               var table_id = table['flow-node-inventory:id'];\r
593 \r
594               if(table.hasOwnProperty('flow-node-inventory:flow')) {\r
595                   table['flow-node-inventory:flow'].forEach(function(flow) {\r
596                       var flowOjb = { table: table_id };\r
597                       flowOjb.flow = flow['flow-node-inventory:id'];\r
598                       flowOjb.data = flow;\r
599                       flowOjb.label = 'table:'+flowOjb.table+' > flow:'+flowOjb.flow;\r
600                       flows.push(flowOjb);\r
601                   });\r
602               }\r
603           });\r
604 \r
605           return flows;\r
606       };\r
607 \r
608       return utils;\r
609 \r
610   });\r
611 });\r