24681e8d4903ce3ac63afd73c831daff977191fb
[Evergreen.git] / Open-ILS / web / reports / xul / template-config.js
1 function removeReportAtom (args) {
2         if (!args) args = {};
3
4         var active_tab = filterByAttribute(
5                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
6                 'selected',
7                 'true'
8         )[0];
9         var tabname = active_tab.getAttribute('id');
10
11         var tabpanel = $( tabname + 'panel' );
12         var tree = tabpanel.getElementsByTagName('tree')[0];
13         var fields = getSelectedItems(tree);
14
15
16         for (var i in fields) {
17                 var field = fields[i];
18                 var colname = field.firstChild.firstChild.nextSibling.getAttribute('label');
19                 var relation_alias = field.getAttribute('relation');
20
21                 delete rpt_rel_cache[relation_alias].fields[tabname][colname];
22                 if (tabname == 'dis_tab') {
23                         var _o_tmp = [];
24                         for each (var _o_col in rpt_rel_cache.order_by) {
25                                 if (_o_col.relation == relation_alias && _o_col.field == colname) continue;
26                                 _o_tmp.push( _o_col );
27                         }
28                         rpt_rel_cache.order_by = _o_tmp
29                 }
30
31                 with (rpt_rel_cache[relation_alias].fields) {
32                         if ( getKeys(dis_tab).length == 0 && getKeys(filter_tab).length == 0 && getKeys(aggfilter_tab).length == 0 )
33                                 delete rpt_rel_cache[relation_alias];
34                 }
35         }
36
37         renderSources();
38
39         return true;
40 }
41
42 function getSourceDefinition(class) {
43         var class_obj = getIDLClass(class);
44         return class_obj.getAttributeNS(persistNS,'tablename') || '(' + class_obj.getElementsByTagNameNS(persistNS,'source_definition')[0].nodeValue + ')';
45 }
46
47 function addReportAtoms () {
48         var nope = $( 'source-add' ).getAttribute('disabled');
49         if (nope == 'true') return false;
50
51         var class_tree = $('class-view');
52         var transform_tree = $('trans-view');
53
54         var active_tab = filterByAttribute(
55                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
56                 'selected',
57                 'true'
58         )[0];
59
60         var tabname = active_tab.getAttribute('id')
61
62         var items = getSelectedItems(class_tree);
63         var transform = getSelectedItems(transform_tree)[0];
64
65         var reltype = $('path-label').getAttribute('reltype');
66         var class_label = $('path-label').value;
67         var relation_alias = hex_md5(class_label);
68
69         for (var i in items) {
70                 var item = items[i];
71
72                 var class_path = item.getAttribute('fullpath');
73                 var field_class = item.getAttribute('idlclass');
74                 var datatype = item.getAttribute('datatype');
75                 var colname = item.getAttribute('idlfield');
76                 var field_label = item.firstChild.firstChild.getAttribute('label');
77
78                 var table_name = getSourceDefinition(field_class);
79
80                 if ( !rpt_rel_cache[relation_alias] ) {
81                         rpt_rel_cache[relation_alias] =
82                                 { label : class_label,
83                                   alias : relation_alias,
84                                   path  : class_path,
85                                   reltype  : reltype,
86                                   idlclass  : field_class,
87                                   table : table_name,
88                                   fields: { dis_tab : {}, filter_tab : {}, aggfilter_tab : {} }
89                                 };
90                 }
91
92                 if ( !rpt_rel_cache[relation_alias].fields[tabname][colname] ) {
93                         rpt_rel_cache[relation_alias].fields[tabname][colname] =
94                                 { colname   : colname,
95                                   transform : (transform && transform.getAttribute('name')) || 'Bare',
96                                   aggregate : transform && transform.getAttribute('aggregate'),
97                                   params    : transform && transform.getAttribute('params'),
98                                   transform_label: (transform && transform.getAttribute('alias')) || 'Raw Data',
99                                   alias     : field_label,
100                                   datatype  : datatype,
101                                   op        : '=',
102                                   op_label  : 'Equals',
103                                   op_value  : {},
104                                 };
105
106                         if (!rpt_rel_cache.order_by)
107                                 rpt_rel_cache.order_by = [];
108
109                         if (tabname == 'dis_tab')
110                                 rpt_rel_cache.order_by.push( { relation : relation_alias, field : colname } );
111
112                 } else if (
113                         confirm(
114                                 'You have already added the [' + field_label +
115                                 '] field\nfrom the [' + class_label + '] source. Click OK if you\nwould like ' +
116                                 'to reset this field.'
117                         )
118                 ) {
119                         rpt_rel_cache[relation_alias].fields[tabname][colname] =
120                                 { colname   : colname,
121                                   transform : (transform && transform.getAttribute('name')) || 'Bare',
122                                   aggregate : transform && transform.getAttribute('aggregate'),
123                                   params    : transform && transform.getAttribute('params'),
124                                   transform_label: (transform && transform.getAttribute('alias')) || 'Raw Data',
125                                   alias     : field_label,
126                                   datatype  : datatype,
127                                   op        : '=',
128                                   op_label  : 'Equals',
129                                   op_value  : {},
130                                 };
131                 }
132         }
133
134         renderSources();
135
136         return true;
137 }
138
139 function changeDisplayOrder (dir) {
140         var active_tab = filterByAttribute(
141                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
142                 'selected',
143                 'true'
144         )[0];
145
146         var tabname = active_tab.getAttribute('id');
147
148         var tabpanel = $( tabname + 'panel' );
149         var tree = tabpanel.getElementsByTagName('tree')[0];
150         var item = getSelectedItems(tree)[0];
151
152         var item_pos = tree.view.selection.currentIndex;
153
154         if (dir == 'u') {
155                 if ( item.previousSibling ) {
156                         item.parentNode.insertBefore( item, item.previousSibling );
157                         item_pos--;
158                 }
159         } else if (dir == 'd') {
160                 if ( item.nextSibling ) {
161                         if (item.nextSibling.nextSibling ) item.parentNode.insertBefore( item, item.nextSibling.nextSibling );
162                         else item.parentNode.appendChild( item );
163                         item_pos++;
164                 }
165         }
166         
167         rpt_rel_cache.order_by = [];
168         var ordered_list = tree.getElementsByTagName('treeitem');
169         for (var i = 0; i < ordered_list.length; i++) {
170                 rpt_rel_cache.order_by.push(
171                         { relation : ordered_list[i].getAttribute('relation'),
172                           field    : ordered_list[i].firstChild.firstChild.nextSibling.getAttribute('label')
173                         }
174                 );
175         }
176
177         tree.view.selection.select( item_pos );
178         return true;
179 }
180
181 function alterColumnLabel () {
182         var active_tab = filterByAttribute(
183                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
184                 'selected',
185                 'true'
186         )[0];
187
188         var tabname = active_tab.getAttribute('id');
189
190         var tabpanel = $( tabname + 'panel' );
191         var tree = tabpanel.getElementsByTagName('tree')[0];
192         var item_pos = tree.view.selection.currentIndex;
193
194         var item = getSelectedItems(tree)[0];
195         var relation_alias = item.getAttribute('relation');
196
197         var field = item.firstChild.firstChild;
198         var colname = field.nextSibling.getAttribute('label');
199
200         var new_label = prompt(
201                 "Change the column header to:",
202                 field.getAttribute("label")
203         );
204
205         if (new_label) {
206                 rpt_rel_cache[relation_alias].fields[tabname][colname].alias = new_label;
207                 renderSources(true);
208                 tree.view.selection.select( item_pos );
209                 tree.focus();
210                 tree.click();
211         }
212
213         return true;
214 }
215
216 function alterColumnTransform (trans) {
217
218         var transform = OILS_RPT_TRANSFORMS[trans];
219
220         var active_tab = filterByAttribute(
221                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
222                 'selected',
223                 'true'
224         )[0];
225
226         var tabname = active_tab.getAttribute('id');
227
228         var tabpanel = $( tabname + 'panel' );
229         var tree = tabpanel.getElementsByTagName('tree')[0];
230         var item_pos = tree.view.selection.currentIndex;
231         var item =  getSelectedItems(tree)[0];
232         var relation_alias = item.getAttribute('relation');
233
234         var field = item.firstChild.firstChild;
235         var colname = field.nextSibling.getAttribute('label');
236
237         rpt_rel_cache[relation_alias].fields[tabname][colname].transform = trans;
238         rpt_rel_cache[relation_alias].fields[tabname][colname].aggregate = transform.aggregate;
239         rpt_rel_cache[relation_alias].fields[tabname][colname].params = transform.params;
240         rpt_rel_cache[relation_alias].fields[tabname][colname].transform_label = transform.label;
241
242         renderSources(true);
243         tree.view.selection.select( item_pos );
244         tree.focus();
245         tree.click();
246
247         $(tabname + '_trans_menu').hidePopup();
248         return true;
249 }
250
251 function changeOperator (args) {
252
253         var active_tab = filterByAttribute(
254                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
255                 'selected',
256                 'true'
257         )[0];
258
259         var tabname = active_tab.getAttribute('id');
260
261         var tabpanel = $( tabname + 'panel' );
262         var tree = tabpanel.getElementsByTagName('tree')[0];
263         var item_pos = tree.view.selection.currentIndex;
264         var item = getSelectedItems(tree)[0];
265
266         var relation_alias = item.getAttribute('relation');
267
268         var field = item.firstChild.firstChild;
269         var colname = field.nextSibling.getAttribute('label');
270
271         rpt_rel_cache[relation_alias].fields[tabname][colname].op = args.op;
272         rpt_rel_cache[relation_alias].fields[tabname][colname].op_label = args.label;
273
274         renderSources(true);
275         tree.view.selection.select( item_pos );
276         tree.focus();
277         tree.click();
278
279         $(tabname + '_op_menu').hidePopup();
280         return true;
281 }
282
283 function removeTemplateFilterValue () {
284
285         var active_tab = filterByAttribute(
286                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
287                 'selected',
288                 'true'
289         )[0];
290
291         var tabname = active_tab.getAttribute('id');
292
293         var tabpanel = $( tabname + 'panel' );
294         var tree = tabpanel.getElementsByTagName('tree')[0];
295         var item_pos = tree.view.selection.currentIndex;
296         var items = getSelectedItems(tree);
297
298         for (var i in items) {
299                 var item = items[i];
300                 var relation_alias = item.getAttribute('relation');
301
302                 var field = item.firstChild.firstChild;
303                 var colname = field.nextSibling.getAttribute('label');
304
305                 rpt_rel_cache[relation_alias].fields[tabname][colname].op_value = {};
306         }
307
308         renderSources(true);
309         tree.view.selection.select( item_pos );
310         return true;
311 }
312
313 function timestampSetDate (obj, cal, date) {
314         obj.op_value.value = date;
315         obj.op_value.object = cal.date;
316         obj.op_value.label = '"' + date + '"';
317
318         renderSources(true);
319         return true;
320 }
321
322 var __handler_cache;
323
324 function changeTemplateFilterValue () {
325
326         var active_tab = filterByAttribute(
327                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
328                 'selected',
329                 'true'
330         )[0];
331
332         var tabname = active_tab.getAttribute('id');
333
334         var tabpanel = $( tabname + 'panel' );
335         var tree = tabpanel.getElementsByTagName('tree')[0];
336         var items = getSelectedItems(tree);
337
338         var targetCmd = $( tabname + '_value_action' );
339
340         targetCmd.menu = null;
341         targetCmd.command = null;
342         targetCmd.oncommand = null;
343         targetCmd.removeEventListener( 'command', __handler_cache, true );
344
345         for (var i in items) {
346                 var item = items[i];
347                 var relation_alias = item.getAttribute('relation');
348
349                 var field = item.firstChild.firstChild;
350                 var colname = field.nextSibling.getAttribute('label');
351
352                 var obj = rpt_rel_cache[relation_alias].fields[tabname][colname]
353                 var operation = OILS_RPT_FILTERS[obj.op];
354
355                 switch (obj.datatype) {
356                         case 'timestamp':
357                                 var cal_popup = $('calendar-widget');
358
359                                 while (cal_popup.firstChild) cal_popup.removeChild(cal_popup.lastChild);
360                                 var calendar = new Calendar(
361                                         0,
362                                         obj.op_value.object,
363                                         function (cal,date) { return timestampSetDate(obj,cal,date) },
364                                         function (cal) { cal_popup.hidePopup(); cal.destroy(); return true; }
365                                 );
366
367                                 var format = OILS_RPT_TRANSFORMS[obj.transform].cal_format || '%Y-%m-%d';
368
369                                 calendar.setDateFormat(format);
370                                 calendar.create(cal_popup);
371
372                                 targetCmd.menu = 'calendar-widget';
373
374                                 break;
375
376                         case 'bool':
377
378                                 function __bool_value_event_handler () {
379                                         var state, answer;
380
381                                         try {
382                                                 // get a reference to the prompt service component.
383                                                 var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
384                                                                     .getService(Components.interfaces.nsIPromptService);
385
386                                                 // set the buttons that will appear on the dialog. It should be
387                                                 // a set of constants multiplied by button position constants. In this case,
388                                                 // three buttons appear, Save, Cancel and a custom button.
389                                                 var flags=promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0 +
390                                                         promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_1 +
391                                                         promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_2;
392
393                                                 // display the dialog box. The flags set above are passed
394                                                 // as the fourth argument. The next three arguments are custom labels used for
395                                                 // the buttons, which are used if BUTTON_TITLE_IS_STRING is assigned to a
396                                                 // particular button. The last two arguments are for an optional check box.
397                                                 answer = promptService.select(
398                                                         window,
399                                                         "Boolean Value",
400                                                         "Select the value, or cancel:",
401                                                         2, ["True", "False"], state
402                                                 );
403                                         } catch (e) {
404                                                 answer = true;
405                                                 state = confirm("Click OK for TRUE and Cancel for FALSE.");
406                                                 state ? state = 0 : state = 1;
407                                         }
408
409                                         if (answer) {
410                                                 if (state) {
411                                                         obj.op_value.value = 'f';
412                                                         obj.op_value.label = 'False';
413                                                 } else {
414                                                         obj.op_value.value = 't';
415                                                         obj.op_value.label = 'True';
416                                                 }
417                                         }
418
419                                         targetCmd.removeEventListener( 'command', __bool_value_event_handler, true );
420                                         renderSources(true);
421                                         tree.view.selection.select( item_pos );
422                                         return true;
423                                 }
424
425                                 __handler_cache = __bool_value_event_handler;
426                                 targetCmd.addEventListener( 'command', __bool_value_event_handler, true );
427
428                                 break;
429
430                         default:
431
432
433                                 var promptstring = "Field does not match one of list (comma separated):";
434
435                                 switch (obj.op) {
436                                         case 'not between':
437                                                 promptstring = "Field value is not between (comma separated):";
438                                                 break;
439
440                                         case 'between':
441                                                 promptstring = "Field value is between (comma separated):";
442                                                 break;
443
444                                         case 'not in':
445                                                 promptstring = "Field does not match one of list (comma separated):";
446                                                 break;
447
448                                         case 'in':
449                                                 promptstring = "Field matches one of list (comma separated):";
450                                                 break;
451
452                                         default:
453                                                 promptstring = "Value " + obj.op_label + ":";
454                                                 break;
455                                 }
456
457                                 function __default_value_event_handler () {
458                                         var _v;
459                                         if (_v  = prompt( promptstring, obj.op_value.value || '' )) {
460                                                 switch (obj.op) {
461                                                         case 'between':
462                                                         case 'not between':
463                                                         case 'not in':
464                                                         case 'in':
465                                                                 obj.op_value.value = _v.split(/\s*,\s*/);
466                                                                 break;
467
468                                                         default:
469                                                                 obj.op_value.value = _v;
470                                                                 break;
471                                                 }
472
473                                                 obj.op_value.label = '"' + obj.op_value.value + '"';
474                                         }
475
476                                         targetCmd.removeEventListener( 'command', __default_value_event_handler, true );
477                                         renderSources(true);
478                                         tree.view.selection.select( item_pos );
479                                         return true;
480                                 }
481
482                                 __handler_cache = __default_value_event_handler;
483                                 targetCmd.addEventListener( 'command', __default_value_event_handler, true );
484
485                                 break;
486                 }
487         }
488
489         return true;
490 }
491
492 function populateOperatorContext () {
493
494         var active_tab = filterByAttribute(
495                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
496                 'selected',
497                 'true'
498         )[0];
499
500         var tabname = active_tab.getAttribute('id');
501
502         var tabpanel = $( tabname + 'panel' );
503         var tree = tabpanel.getElementsByTagName('tree')[0];
504         var items = getSelectedItems(tree);
505
506         var dtypes = [];
507         for (var i in items) {
508                 var item = items[i];
509                 dtypes.push( item.getAttribute('datatype') );
510         }
511
512         var menu = $(tabname + '_op_menu');
513         while (menu.firstChild) menu.removeChild(menu.lastChild);
514
515         for (var i in OILS_RPT_FILTERS) {
516                 var o = OILS_RPT_FILTERS[i];
517                 menu.appendChild(
518                         createMenuItem(
519                                 { label : o.label,
520                                   onmouseup : "changeOperator({op:'"+i+"',label:'"+o.label+"'})"
521                                 }
522                         )
523                 );
524                 if (o.labels) {
525                         var keys = getKeys(o.labels);
526                         for ( var k in keys ) {
527                                 var key = keys[k];
528                                 if ( grep(function(x){return key==x},dtypes).length ) {
529                                         menu.appendChild(
530                                                 createMenuItem(
531                                                         { label : o.labels[key],
532                                                           onmouseup : "changeOperator({op:'"+i+"',label:'"+o.labels[key]+"'});"
533                                                         }
534                                                 )
535                                         );
536                                 }
537                         }
538                 }
539         }
540 }
541
542 function populateTransformContext () {
543
544         var active_tab = filterByAttribute(
545                 $('used-source-fields-tabbox').getElementsByTagName('tab'),
546                 'selected',
547                 'true'
548         )[0];
549
550         var tabname = active_tab.getAttribute('id');
551
552         var tabpanel = $( tabname + 'panel' );
553         var tree = tabpanel.getElementsByTagName('tree')[0];
554         var items = getSelectedItems(tree);
555
556         var transforms = {};
557         for (var i in items) {
558                 var item = items[i];
559                 var dtype = item.getAttribute('datatype');
560                 var item_transforms = getTransforms({ datatype : dtype });
561
562                 for (var j in item_transforms) {
563                         transforms[item_transforms[j]] = OILS_RPT_TRANSFORMS[item_transforms[j]];
564                         transforms[item_transforms[j]].name = item_transforms[j];
565                 }
566         }
567
568         var transformList = [];
569         for (var i in transforms) {
570                 transformList.push( transforms[i] );
571         }
572
573         transformList.sort( sortHashLabels );
574
575         var menu = $(tabname + '_trans_menu');
576         while (menu.firstChild) menu.removeChild(menu.lastChild);
577
578         for (var i in transformList) {
579                 var t = transformList[i];
580
581                 if (tabname.match(/filter/)) {
582                         if (tabname.match(/^agg/)) {
583                                 if (!t.aggregate) continue;
584                         } else {
585                                 if (t.aggregate) continue;
586                         }
587                 }
588
589                 menu.appendChild(
590                         createMenuItem(
591                                 { aggregate : t.aggregate,
592                                   name : t.name,
593                                   alias : t.label,
594                                   label : t.label,
595                                   params : t.params,
596                                   onmouseup : "alterColumnTransform('"+t.name+"')"
597                                 }
598                         )
599                 );
600         }
601
602         menu.parentNode.setAttribute('disabled','false');
603         if (menu.childNodes.length == 0) {
604                 menu.parentNode.setAttribute('disabled','true');
605         }
606 }
607
608
609 function renderSources (selected) {
610
611         var tree = $('used-sources');
612         var sources = $('used-sources-treetop');
613         var tabs = $('used-source-fields-tabbox').getElementsByTagName('tab');
614
615         if (!selected) {
616                 while (sources.firstChild) sources.removeChild(sources.lastChild);
617         } else {
618                 selected = getSelectedItems(tree);
619                 if (!selected.length) {
620                         selected = undefined;
621                         while (sources.firstChild) sources.removeChild(sources.lastChild);
622                 }
623         }
624
625         for (var j = 0; j < tabs.length; j++) {
626                 var tab = tabs[j];
627                 var tabname = tab.getAttribute('id')
628                 var tabpanel = $( tab.getAttribute('id') + 'panel' );
629                 var fieldtree = tabpanel.getElementsByTagName('treechildren')[0];
630
631                 while (fieldtree.firstChild) fieldtree.removeChild(fieldtree.lastChild);
632         }
633
634         for (var relation_alias in rpt_rel_cache) {
635                 if (!rpt_rel_cache[relation_alias].fields) continue;
636
637                 if (selected) {
638                         if (
639                                 !grep(
640                                         function (x) {
641                                                 return x.getAttribute('relation') == relation_alias;
642                                         },
643                                         selected
644                                 ).length
645                         ) continue;
646                 } else {
647
648                         $('used-sources-treetop').appendChild(
649                                 createTreeItem(
650                                         { relation : rpt_rel_cache[relation_alias].alias,
651                                           idlclass : rpt_rel_cache[relation_alias].idlclass,
652                                           reltype  : rpt_rel_cache[relation_alias].reltype,
653                                           path     : rpt_rel_cache[relation_alias].path,
654                                         },
655                                         createTreeRow(
656                                                 {},
657                                                 createTreeCell({ label : rpt_rel_cache[relation_alias].label }),
658                                                 createTreeCell({ label : rpt_rel_cache[relation_alias].table }),
659                                                 createTreeCell({ label : rpt_rel_cache[relation_alias].alias }),
660                                                 createTreeCell({ label : rpt_rel_cache[relation_alias].reltype })
661                                         )
662                                 )
663                         );
664                 }
665
666                 for each (var tabname in ['filter_tab','aggfilter_tab']) {
667                         tabpanel = $( tabname + 'panel' );
668                         fieldtree = tabpanel.getElementsByTagName('treechildren')[0];
669
670                         for (var colname in rpt_rel_cache[relation_alias].fields[tabname]) {
671                                 with (rpt_rel_cache[relation_alias].fields[tabname][colname]) {
672                                         fieldtree.appendChild(
673                                                 createTreeItem(
674                                                         { relation : relation_alias, datatype : datatype },
675                                                         createTreeRow(
676                                                                 {},
677                                                                 createTreeCell({ label : alias }),
678                                                                 createTreeCell({ label : colname }),
679                                                                 createTreeCell({ label : datatype }),
680                                                                 createTreeCell({ label : transform_label }),
681                                                                 createTreeCell({ label : transform })
682                                                         )
683                                                 )
684                                         );
685
686                                         fieldtree.lastChild.firstChild.appendChild(
687                                                 createTreeCell({ op : op, label : op_label })
688                                         );
689
690                                         if (op_value.value != undefined) {
691                                                 fieldtree.lastChild.firstChild.appendChild(
692                                                         createTreeCell({ label : op_value.label })
693                                                 );
694                                         }
695                                 }
696                         }
697                 }
698         }
699
700         tabpanel = $( 'dis_tabpanel' );
701         fieldtree = tabpanel.getElementsByTagName('treechildren')[0];
702         for each (var order in rpt_rel_cache.order_by) {
703
704                 if (selected) {
705                         if (
706                                 !grep(
707                                         function (x) {
708                                                 return x.getAttribute('relation') == order.relation;
709                                         },
710                                         selected
711                                 ).length
712                         ) continue;
713                 }
714
715                 with (rpt_rel_cache[order.relation].fields.dis_tab[order.field]) {
716                         fieldtree.appendChild(
717                                 createTreeItem(
718                                         { relation : order.relation, datatype : datatype },
719                                         createTreeRow(
720                                                 {},
721                                                 createTreeCell({ label : alias }),
722                                                 createTreeCell({ label : colname }),
723                                                 createTreeCell({ label : datatype }),
724                                                 createTreeCell({ label : transform_label }),
725                                                 createTreeCell({ label : transform })
726                                         )
727                                 )
728                         );
729
730                         fieldtree.lastChild.firstChild.appendChild(
731                                 createTreeCell({ op : op, label : op_label })
732                         );
733
734                         if (op_value.value != undefined) {
735                                 fieldtree.lastChild.firstChild.appendChild(
736                                         createTreeCell({ label : op_value.label })
737                                 );
738                         }
739                 }
740         }
741 }
742
743 var param_count;
744 var tab_use = {
745         dis_tab       : 'select',
746         filter_tab    : 'where',
747         aggfilter_tab : 'having',
748 };
749
750
751 function save_template () {
752         param_count = 0;
753
754         var template = {
755                 version    : 2,
756                 core_class : $('sources-treetop').getElementsByTagName('treeitem')[0].getAttribute('idlclass'),
757                 select     : [],
758                 from       : {},
759                 where      : [],
760                 having     : [],
761                 order_by   : []
762         };
763
764         for (var relname in rpt_rel_cache) {
765                 var relation = rpt_rel_cache[relname];
766                 if (!relation.fields) continue;
767
768                 // first, add the where and having clauses (easier)
769                 for each (var tab_name in [ 'filter_tab', 'aggfilter_tab' ]) {
770                         var tab = relation.fields[tab_name];
771                         for (var field in tab) {
772                                 fleshTemplateField( template, relation, tab_name, field );
773                         }
774                 }
775
776                 // now the from clause
777                 fleshFromPath( template, relation );
778         }
779
780         // and now for select (based on order_by)
781         for each (var order in rpt_rel_cache.order_by)
782                 fleshTemplateField( template, rpt_rel_cache[order.relation], 'dis_tab', order.field );
783
784         template.rel_cache = rpt_rel_cache;
785
786         //prompt( 'template', js2JSON( template ) );
787
788         // and the saving throw ...
789         var cgi = new CGI();
790         var session = cgi.param('ses');
791         fetchUser( session );
792
793         var tmpl = new rt();
794         tmpl.name( $('template-name').value );
795         tmpl.description( $('template-description').value );
796         tmpl.owner(USER.id());
797         tmpl.folder(cgi.param('folder'));
798         tmpl.data(js2JSON(template));
799
800         if(!confirm('Name : '+tmpl.name() + '\nDescription: ' + tmpl.description()+'\nSave Template?'))
801                 return;
802
803         var req = new Request('open-ils.reporter:open-ils.reporter.template.create', session, tmpl);
804         req.request.alertEvent = false;
805         req.callback(
806                 function(r) {
807                         var res = r.getResultObject();
808                         if(checkILSEvent(res)) {
809                                 alertILSEvent(res);
810                         } else {
811                                 if( res && res != '0' ) {
812                                         confirm('Template ' + tmpl.name() + ' was successfully saved.');
813                                         _l('../oils_rpt.xhtml');
814                                 }
815                         }
816                 }
817         );
818
819         req.send();
820 }
821
822 function fleshFromPath ( template, rel ) {
823         var table_path = rel.path.split( /\./ );
824         if (table_path.length > 1 || rel.path.indexOf('-') > -1) table_path.push( rel.idlclass );
825
826         var prev_type = '';
827         var prev_link = '';
828         var current_path = '';
829         var current_obj = template.from;
830         var link;
831         while (link = table_path.shift()) {
832                 if (current_path) current_path += '-';
833                 current_path += link;
834
835                 var leaf = table_path.length == 0 ? true : false;
836
837                 current_obj.path = current_path;
838                 current_obj.table = getSourceDefinition( link.split(/-/)[0] );
839
840                 if (prev_link != '') {
841                         var prev_class = getIDLClass( prev_link.split(/-/)[0] );
842                         var prev_field = prev_link.split(/-/)[1];
843
844                         var current_link = getIDLLink( prev_class, prev_field );
845                         current_obj.key = current_link.getAttribute('key');
846
847                         if (
848                                 (
849                                         current_link.getAttribute('reltype') != 'has_a' ||
850                                         prev_type == 'left' ||
851                                         rel.reltype != 'has_a'
852                                 ) && (
853                                         getKeys(rel.fields.filter_tab).length == 0 &&
854                                         getKeys(rel.fields.aggfitler_tab).length == 0
855                                 )
856                         ) current_obj.type = 'left';
857
858                         prev_type = current_obj.type; 
859                 }
860
861                 if (leaf) {
862                         current_obj.label = rel.label;
863                         current_obj.alias = rel.alias;
864                         current_obj.idlclass = rel.idlclass;
865                         current_obj.template_path = rel.path;
866                 } else {
867                         var current_class = getIDLClass( link.split(/-/)[0] );
868                         var join_field = link.split(/-/)[1];
869                         var join_link = getIDLLink(current_class, join_field);
870
871                         if (join_link.getAttribute('reltype') != 'has_a') {
872                                 var fields_el = current_class.getElementsByTagName('fields')[0];
873                                 join_field =
874                                         fields_el.getAttributeNS(persistNS, 'primary') +
875                                         '-' + join_link.getAttribute('class') +
876                                         '-' + join_link.getAttribute('key');
877                         }
878
879                         if (!current_obj.alias) current_obj.alias = hex_md5( current_path ) ;
880                         join_field += '-' + current_obj.alias;
881
882                         if (!current_obj.join) current_obj.join = {};
883                         if (!current_obj.join[join_field]) current_obj.join[join_field] = {};
884
885                         if (current_obj.type == 'left') current_obj.join[join_field].type = 'left';
886
887                         current_obj = current_obj.join[join_field];
888                 }
889
890                 prev_link = link;
891         }
892
893
894 }
895
896 function fleshTemplateField ( template, rel, tab_name, field ) {
897
898         if (!rel.fields[tab_name] || !rel.fields[tab_name][field]) return;
899
900         var tab = rel.fields[tab_name];
901
902         var table_path = rel.path.split( /\./ );
903         if (table_path.length > 1 || rel.path.indexOf('-') > -1)
904                 table_path.push( rel.idlclass );
905
906         table_path.push( field );
907
908         var field_path = table_path.join('-');
909
910         var element = {
911                 alias : tab[field].alias,
912                 column :
913                         { colname : field,
914                           transform : tab[field].transform,
915                           transform_label : tab[field].transform_label
916                         },
917                 path : field_path,
918                 relation : rel.alias
919         };
920
921         if (tab_name.match(/filter/)) {
922                 element.condition = {};
923                 if (tab[field].op == 'is' || tab[field].op == 'is not' || tab[field].op == 'is blank' || tab[field].op == 'is not blank') {
924                         element.condition[tab[field].op] = null;
925                 } else {
926                         element.condition[tab[field].op] =
927                                 tab[field].op_value.value ?
928                                         tab[field].op_value.value :
929                                         '::P' + param_count++;
930                 }
931         }
932
933         template[tab_use[tab_name]].push(element);
934 }
935