source: trunk/prototype/api/datalayer.js @ 5615

Revision 5615, 121.5 KB checked in by acoutinho, 12 years ago (diff)

Ticket #2434 - Remocao do importe de arquivos da agenda na inicializacao do modulo expressoMail e correcoes de bugs

  • Property svn:executable set to *
Line 
1internalUrl = /^([A-z0-9-_]+)(:[A-z0-9-_]+)?$/;
2internalUri = /^([a-zA-Z0-9-_]+)\(([a-zA-Z0-9-_]+)\):\/\/(.*)|([a-zA-Z0-9-_]+):\/\/(.*)$/;
3isGeneratedId = /^\d+\(javascript\)$/;
4arrayName = /^([A-z0-9-_]+)\[\]$/;
5startsDoubleDot = /^:/;
6isIframe = /^iframe.*/;
7FILE = 'files';
8// cached_urls = {};
9
10$.ajaxPrefilter(function( options, originalOptions, jqXHR ){
11
12      if( options.url != 'undefined' && internalUrl.test( options.url ) ){
13
14//        if( !cached_urls[options.url] )
15//            return;
16//        alert( options.url + " dentro" );
17
18           var callback = ( options.success || options.complete || $.noop );
19
20          if( isIframe.test( options.dataType ) || options.data instanceof FormData )
21          {
22              options.url = options.fileInput.parents( 'form' ).attr( 'action' );
23           
24              res = internalUrl.exec( options.url );
25
26              var data = {};
27
28              data[ res[1] ] = DataLayer.form( options.fileInput.parents( 'form' ), options.fileInput );
29
30              options.formData = DataLayer.serializeForm( data );
31
32              callback = function( data ){
33
34                    //coutinho, escreva seu codigo aqui.
35
36                    return callback( DataLayer.encode( res[2], data ) );
37
38              }
39
40              options.url = DataLayer.dispatchPath + 'post.php';
41
42              if( options.data instanceof FormData )
43              {
44                  options.data = new FormData();
45
46                  $.each(options.formData, function (index, field) {
47                            options.data.append(field.name, field.value);
48                        });
49                 
50                  $.each(options.files, function (index, file) {
51                            options.data.append(options.paramName, file);
52                        });
53              }
54
55              return( true );
56          }
57
58          jqXHR.abort();
59
60          switch( options.type.toUpperCase() )
61          {
62            case 'GET':
63                  return callback( DataLayer.get( options.url, /*false,*/ options.data ) );
64
65            case 'POST':
66                  return callback( DataLayer.put( options.url, options.data ) );
67          }
68
69          //return( false );
70
71//        options.url = params[1];
72//        options.data = ( options.data || "" ) + "&" + params[2];
73      }
74
75});
76
77// $("a").live("click", function( event ){
78//
79//     event.preventDefault();
80//
81//     $.ajax({
82//
83//     
84//
85//     });
86//
87// });
88
89$("form").live( "submit", function( event ){
90
91    var $this = $(this), action = $this.attr('action'), res = false,
92   
93    method = $this.attr( 'method' ) || 'POST',
94   
95    fileInputs = $this.find('input[type="file"]');
96   
97    if( fileInputs.length && !$this.is('[enctype="multipart/form-data"]') )
98    {
99        event.preventDefault();
100
101        DataLayer.send( action,
102                        [ method, 'iframe json' ], {},
103                        //TODO: check the type for conversion
104                        DataLayer.receive,
105                        false, { 'formData': $this.serializeArray(),  'fileInput': fileInputs, 'paramName': FILE + '[]' } );
106
107        return( false );
108    }
109   
110    if( res = internalUrl.exec( action ) )
111    {
112        event.preventDefault();
113
114        var data = DataLayer.form( this );
115       
116        switch( method.toUpperCase() )
117        {
118          case 'GET':
119                DataLayer.get( res[0], data );
120
121          case 'POST':
122                DataLayer.put( res[1], data );
123        }
124
125        return( false );
126    }
127
128    return( true );
129});
130
131this.storage = new $.store();
132
133DataLayer = {
134
135    links: {},
136    nestedLinks: {},
137    concepts: {},
138    listeners: {},
139    encoders: {},
140    decoders: {},
141    templates: {},
142    criterias: {},
143    tasks: [],
144
145    render: function( templateName, data, filter, formatter, force ){
146
147        if( $.isFunction( filter ) )
148        {
149            force = formatter;
150            formatter = filter;
151            filter = false;
152        }
153
154        if( typeof data === "string" )
155        {
156            data = this.get( data, filter, force ) || {};
157        }
158       
159        var formatting = function( template ){
160
161              if( template === false ) return( false );
162
163              if( template )
164                  DataLayer.templates[ templateName ] = new EJS({ text: template, cache: false });
165
166              var html = DataLayer.templates[ templateName ].render( { data: data } );
167
168              if( !formatter )
169                  return( html );
170
171              return formatter( html );
172        }
173
174        if( this.templates[ templateName ] )
175        {
176            return formatting();
177        }
178
179        return this.send( DataLayer.templatePath + templateName, 'get', false, formatting, !!!formatter );
180    },
181   
182    send: function( url, type, data, callback, sync, extraOptions ){
183     
184          var result = false, fired = false;
185     
186          var envelope = {
187
188              'async': ( typeof sync !== "undefined" ? !sync : !!callback ),
189              'url': url,
190              'success': function( dt, textStatus, jqXHR ){
191
192                    if( callback )
193                    {
194                        fired = true;
195                        result = callback( dt, textStatus, jqXHR );
196                    }
197                    else
198                        result = dt;
199
200                },
201              'complete': function( jqXHR, textStatus ){
202
203                  if( !fired && callback )
204                      result = callback( false, textStatus, jqXHR );
205
206              },
207
208              'type': $.isArray( type ) ? type[0] : type,
209              'data': data
210
211            };
212
213          if( $.isArray( type ) && type[1] )
214              envelope['dataType'] = type[1];
215
216          if( extraOptions )
217              envelope = $.extend( envelope, extraOptions );
218
219          $.ajax( envelope );
220     
221          return( result );
222    },
223   
224    dispatch: function( dispatcher, data, callback, isPost, dataType ){
225     
226      return this.send( this.dispatchPath + dispatcher + ".php",
227                        [ ( isPost ? 'post' : 'get' ), dataType || 'json' ],
228                        data,
229                        callback );
230
231//       $.ajax({
232//            'async': !!callback,
233//            'url': this.dispatchPath + dispatcher + ".php",
234//            'type': ( isPost ? 'post' : 'get' ),
235//            'dataType': 'json',
236//            'data': data,
237//            'success': function( dt, textStatus, jqXHR ){
238//
239//                  if( callback )
240//                  {
241//                      fired = true;
242//                      callback( dt, textStatus, jqXHR );
243//                  }
244//                  else
245//                      result = dt;
246//
247//              },
248//            'complete': function( jqXHR, textStatus ){
249//
250//                if( !fired && callback )
251//                    callback( false, textStatus, jqXHR );
252//
253//            }/*,
254//            'processData': false*/
255//        });
256
257      //return( result );
258    },
259
260    form: function( target, fileInputs ){
261
262        var params = {}, $this = $(target), inputArray = $this.serializeArray();
263
264        if( !$this.is( "form" ) )
265            $this = $this.parents( "form" );
266               
267        if( fileInputs )
268                fileInputs.each( function( i, el ){
269
270              inputArray[ inputArray.length ] = { name: $(this).prop("name"), value: FILE + i };
271
272                });
273
274        $.each( inputArray, function( i, el ){
275
276            if( newName = arrayName.exec( el.name ) )
277                el.name = newName[1];
278            else if( !params[ el.name ] )
279                return( params[ el.name ] = el.value );
280
281            params[ el.name ] = params[ el.name ] || [];
282
283            if( $.type(params[ el.name ]) !== "array" )
284                params[ el.name ] = [ params[ el.name ] ];
285
286            params[ el.name ].push( el.value );
287        });
288
289//      alert(dump(params));
290
291        return this.decode( $this.attr( "action" ), params );
292    },
293       
294        serializeForm: function( data, level ){
295       
296                var formData = [];
297       
298                for( key in data )
299                {
300                        var value = data[key];
301
302                        if( level !== undefined )
303                                key = level+'['+key+']';
304
305                        if( $.isArray(value) || $.isPlainObject(value) )
306                                formData = formData.concat( this.serializeForm( value, key ) );
307                        else
308                                formData[ formData.length ] = { name: key, value: value };
309                }
310               
311                return( formData );
312        },
313
314    blend: function( action, data ){
315
316//      if( notArray = (!$.isArray(data)) )
317//          data = [ data ];
318
319        var form = $('form[action="'+action+'"]');
320
321        form.get(0).reset();
322
323        var named = form.find( 'input[name]' );
324
325        for( var name in data )
326        {
327            named.filter( '[name="'+name+'"]' ).val( data[name] );
328        }
329    },
330
331 
332   
333    put: function( concept, filter, data, oneSide ){
334     
335      ///////////////////////////// normalize ////////////////////////////////
336        if( arguments.length == 2 )
337        {
338            data = filter;
339            filter = false;
340        }
341        if( typeof data === "undefined" ||
342            $.type(data) === "boolean" )
343        {
344            oneSide = data;
345            data = filter;
346            filter = false;
347        }
348       
349        if( !concept || !data )
350            return( false );
351
352        var decoder = "", id = false, bothSides = (typeof oneSide === "undefined"), notArray, res;
353       
354        if( $.type(filter) === "string" )
355        {
356            id = filter;
357            filter = false;
358        }
359
360        if( id )
361            data.id = id;
362
363        if( notArray = ( $.type( data ) !== "array" ) )
364            data = [ data ];
365
366        if( res = internalUrl.exec( concept ) )
367        {
368            //TODO: verificar se a decodificaçao deve ser feita em cada item do array
369            data = this.decode( concept, data );
370            concept = res[1];
371            decoder = res[2];
372        }
373
374      ////////////////////////////////////////////////////////////////////////
375
376        if( bothSides || !oneSide )
377        {
378            var result = false, links = this.links( concept ), nestedLinks = this.links( concept, true ),
379            current = this.check( concept ) || {}, ids = [];
380
381            for( var i = 0; i < data.length; i++ )
382            {
383                var key = ids[ ids.length ] = data[i].id || this.generateId( concept ), updateSet = {};
384
385                ////////////////////////////// linkage /////////////////////////////////   
386                for( var link in links )
387                {
388                    if( data[i][link] )
389                    {
390                        var isConcept = false;
391                     
392                        if( isConcept = this.isConcept( concept, link ) )
393                            data[i][link] = [ data[i][link] ];
394
395                        var _this = this;
396
397                        $.each( data[i][link], function( ii, el ){
398
399                                var isRef = false;
400
401                                if( isRef = ($.type(el) === "string") )
402                                    el = { id: el };
403
404                                //removido pois o mesmo esta gerando inconsistencia em tudo
405//                              if( DataLayer.isConcept( links[link], nestedLinks[link] ) )
406                                if( isConcept )
407                                {
408                                    el[ nestedLinks[link] ] = el[ nestedLinks[link] ] || [];
409                                    el[ nestedLinks[link] ].push( key );
410                                }
411                                else
412                                    el[ nestedLinks[link] ] = key;
413
414                                if( isRef && ( !current[ key ] || !current[ key ][ link ] ||
415                                               (isConcept ? current[ key ][ link ] !== el.id : !$.inArray( el.id, current[ key ][ link ] )) ) )
416                                {
417                                    updateSet[ links[link] ] = updateSet[ links[link] ] || [];
418                                    updateSet[ links[link] ].push( el );
419                                }
420                                else if( !isRef )
421                                    data[i][link][ii] = _this.put( links[link], el, oneSide );
422                            });
423
424                        if( isConcept )
425                            data[i][link] = data[i][link][0];
426                    }
427                }
428                //////////////////////////////////////////////////////////////////////////
429
430                if( data[i].id )
431                    data[i] = this.merge( current[ data[i].id ], data[i] );
432
433                 current[ key ] = data[i];
434
435                if( bothSides )
436                  this.report( concept, key, data[i] );
437            }
438
439            this.store( concept, current );
440
441            for( var setKey in updateSet )
442            {
443                if( bothSides )
444                    for( var i = 0; i < updateSet[ setKey ].length; i++ )
445                      this.report( setKey, updateSet[ setKey ][i].id, updateSet[ setKey ][i] );
446                   
447                DataLayer.put( setKey, updateSet[ setKey ], false );
448            }
449        }
450
451        if( oneSide )
452            this.commit( concept, ids/*, true */);
453
454        this.broadcast( concept, oneSide ? 'server' : bothSides ? 'serverclient' : 'client', true );
455
456        return( notArray ? ids[0] : ids );
457
458    },
459   
460    remove: function( concept, id, oneSide ){
461     
462        var bothSides = (typeof oneSide === "undefined"),
463
464        links = this.links( concept ), nestedLinks = this.links( concept, true ), ids = [],
465
466        current = this.check( concept, id );
467
468        if( !current ) return;
469       
470        if( typeof id === "string" )
471            current.id = id;
472
473        if( notArray = ( $.type( current ) !== "array" ) )
474            current = [ current ];
475
476        for( var i = 0; i < current.length; i++ )
477        {
478            var currentId = ids[ ids.length ] = current[i].id;
479
480            if( bothSides )
481              this.report( concept, currentId, false );
482
483            if( bothSides || !oneSide )
484              this.del( concept, currentId );
485
486            for( var link in links )
487            {
488                if( !current[i][link] )
489                    continue;
490
491                if( isConcept = this.isConcept( concept, link ) )
492                    current[i][link] = [ current[i][link] ];
493
494                $.each( current[i][link], function( ii, el ){
495
496                        el = DataLayer.storage.cache[links[link]][el];
497
498                        if( notArrayNested = ( $.type( el[ nestedLinks[link] ] ) !== "array" ) )
499                            el[ nestedLinks[link] ] = [ el[nestedLinks[link]] ];
500
501                        el[ nestedLinks[link] ] = $.grep( el[ nestedLinks[link] ], function( nested, iii ){
502                            return ( currentId !== nested );
503                        });
504
505                        if( notArrayNested )
506                            el[ nestedLinks[link] ] = el[ nestedLinks[link] ][0] || false;
507                        if(!el[ nestedLinks[link] ] || !el[ nestedLinks[link] ].length)
508                                delete el[ nestedLinks[link] ];
509                });
510            }
511        }
512
513        if( oneSide )
514            this.commit( concept, ids );
515
516        this.broadcast( concept, oneSide ? 'server' : bothSides ? 'serverclient' : 'client', false );
517    },
518   
519    report: function( concept, id, data )
520    {     
521        var current = this.check( ':current', concept ) || {};
522
523        if( !current[ id ] )
524            current[ id ] = this.check( concept, id ) || {};
525       
526        this.store( ':current', concept, current );
527
528        var diff = this.diff( current[ id ], data );
529
530        var diffs = this.check( ':diff', concept ) || {};
531
532        if( diffs[ id ] )
533            diff = this.merge( diffs[ id ], diff );
534
535        if( !diff || !$.isEmptyObject( diff ) )
536            diffs[ id ] = diff;
537
538        this.store( ':diff', concept, diffs );
539    },
540
541//     enqueue: function( queueName, concept, id, data ){
542//
543//      var queue = this.check( ':' + queueName, concept ) || {};
544//
545//
546//     },
547//     
548//     dequeue: function( queueName, concept, id ){
549//
550//     
551//
552//     },
553   
554   
555   
556    rollback: function( concept, ids ){
557     
558        var queue = this.prepareQ( 'current', concept, ids );
559
560        ids = [];
561
562        for( var id in queue )
563        {
564             this.put( concept, id, queue[id], false );
565
566             ids[ ids.length ] = id;
567        }
568
569        this.clearQ( concept, ( ids.length ? ids : false ) );
570
571        this.broadcast( concept, 'revert' );
572     
573    },
574   
575    prepareQ: function( queueName, concept, ids ){
576     
577      var notArray = false;
578     
579      if( notArray = ($.type(concept) !== "array") )
580          concept = [ concept ];
581     
582      var q = {};
583     
584      for( var i = 0; i < concept.length; i++ )
585      {
586          var queue = this.check( ':' + queueName, concept[i] || false );
587         
588          if( !queue ) continue;
589
590          if( ids )
591          {
592              if( $.type(ids) !== "array" )
593                  ids = [ ids ];
594
595              var filtered = {};
596
597              for( var ii = 0; ii < ids.length; ii++ )
598              {
599                  filtered[ ids[ii] ] = queue[ ids[ii] ];
600              }
601
602              queue = filtered;
603          }
604
605          q[ concept[i] ] = queue;
606      }
607     
608      return( notArray ? q[ concept[0] ] : q );
609    },
610   
611    clearQ: function( concept, ids ){
612     
613        var current = this.check( ':current', concept || false );
614        var diffs = this.check( ':diff', concept || false );
615
616        if( !ids )
617            current = diffs = {};
618        else
619        {
620            if( notArray = ($.type(ids) !== "array") )
621              ids = [ ids ];
622
623            for( var i = 0; i < ids.length; i++ )
624            {
625                delete current[ ids[i] ];
626                delete diffs[ ids[i] ];
627            }
628        }
629
630        this.store( ':current', concept, current );
631        this.store( ':diff', concept, diffs );
632    },
633
634    commit: function( concept, ids, callback ){
635     
636        var queue = this.prepareQ( 'diff', concept, ids );
637
638        this.sync( queue, !$.isArray(concept) && concept || false, callback );
639    },
640   
641    sync: function( queue, concept, callback ){
642
643        if( !queue || $.isEmptyObject( queue ) )
644            return;
645
646        if( concept )
647        {
648          var helper = {};
649          helper[concept] = queue;
650          queue = helper;
651        }
652
653        var data = {}, URIs = {};
654
655        for( var concept in queue )
656            for( var id in queue[concept] )
657            {
658                data[ this.URI( concept, id ) ] = queue[concept][id];
659                URIs[ this.URI( concept, id ) ] = { concept: concept, id: id };
660            }
661
662        if( $.isEmptyObject( data ) )
663            return;
664
665        this.dispatch( "Sync", data, function( data, status, jqXHR ){
666
667//          switch( status )
668//          {
669//            case "error":
670//            case "parsererror":
671//              return DataLayer.rollback( concept, URI );
672//            case "success":
673//              return DataLayer.commit();
674//            case "timeout":
675//            case "notmodified":
676//          }
677
678            var received = DataLayer.receive( data );
679
680            for( var URI in URIs )
681                if( typeof received[URI] !== "undefined" )
682                    DataLayer.clearQ( URIs[URI].concept, URIs[URI].id );
683
684            if( callback )
685                callback( received );
686
687//          for( var URI in data )
688//          {
689//              var parsed = DataLayer.parseURI( URI ),
690//   
691//              concept = parsed[1], id = parsed[3];
692//
693//              if( $.type(data[URI]) === "string" )
694//              {
695//                //TODO:threat the exception thrown
696//                DataLayer.rollback( concept, id );
697//                delete URIs[ URI ];
698//                continue;
699//              }
700//
701//              if( data[URI] === false ){
702//                DataLayer.remove( concept, id, false );
703//                continue;
704//              }
705//
706//              if( id !== data[URI].id )
707//                DataLayer.move( concept, id, data[URI].id );
708//             
709//              DataLayer.put( concept, id, data[URI], false );
710//          }
711//         
712//          for( var URI in URIs )
713//               DataLayer.clearQ( URIs[URI].concept, URIs[URI].id );
714//         
715//          if( callback )
716//              callback();
717
718        }, true );
719
720    },
721   
722    receive: function( data ){
723     
724        var received = {};
725       
726            for( var URI in data )
727            {
728                var parsed = DataLayer.parseURI( URI ),
729   
730            concept = parsed[4], id = parsed[5];
731
732            received[ URI ] = data[ URI ];
733
734                if( $.type(data[URI]) === "string" )
735                {
736                  //TODO:threat the exception thrown
737                  DataLayer.rollback( concept, id );
738                  continue;
739                }
740
741                if( data[URI] === false ){
742                  DataLayer.remove( concept, id, false );
743                  continue;
744                }
745
746                if( id !== data[URI].id )
747                  DataLayer.move( concept, id, data[URI].id );
748               
749                DataLayer.put( concept,  data[URI].id || id, data[URI], false );
750            }
751           
752        return( received );
753           
754    },
755   
756    unique: function( origArr ){
757
758        var newArr = [];
759     
760        for ( var x = 0; x < origArr.length; x++ )
761        {
762                var found = false;
763            for ( var y = 0; !found && y < newArr.length; y++ )
764                if ( origArr[x] === newArr[y] ) 
765                  found = true;
766
767            if ( !found )
768                newArr[ newArr.length ] = origArr[x];
769        }
770
771        return newArr;
772    },
773
774    merge: function( current, data ){
775     
776        return this.copy(  data, current );
777
778//      return $.extend( current, data );
779
780    },
781   
782    // clone objects, skip other types.
783    clone: function(target) {
784            if ( typeof target == 'object' ) {
785                    Clone.prototype = target;
786                    return new Clone();
787            } else {
788                    return target;
789            }
790    },
791     
792    // Shallow Copy
793    shallowCopy: function(target) {
794            if (typeof target !== 'object' ) {
795                    return target;  // non-object have value sematics, so target is already a copy.
796            } else {
797                    var value = target.valueOf();
798                    if (target != value) {
799                            // the object is a standard object wrapper for a native type, say String.
800                            // we can make a copy by instantiating a new object around the value.
801                            return new target.constructor(value);
802                    } else {
803                            // ok, we have a normal object. If possible, we'll clone the original's prototype
804                            // (not the original) to get an empty object with the same prototype chain as
805                            // the original.  If just copy the instance properties.  Otherwise, we have to
806                            // copy the whole thing, property-by-property.
807                            if ( target instanceof target.constructor && target.constructor !== Object ) {
808                                    var c = clone(target.constructor.prototype);
809     
810                                    // give the copy all the instance properties of target.  It has the same
811                                    // prototype as target, so inherited properties are already there.
812                                    for ( var property in target) {
813                                            if (target.hasOwnProperty(property)) {
814                                                    c[property] = target[property];
815                                            }
816                                    }
817                            } else {
818                                    var c = {};
819                                    for ( var property in target ) c[property] = target[property];
820                            }
821                           
822                            return c;
823                    }
824            }
825    },
826
827    // entry point for deep copy.
828    // source is the object to be deep copied.
829    // depth is an optional recursion limit. Defaults to 256.
830    // deep copy handles the simple cases itself: non-objects and object's we've seen before.
831    // For complex cases, it first identifies an appropriate DeepCopier, then delegate the details of copying the object to him.
832    copy: function(source, result, depth) {
833     
834            // null is a special case: it's the only value of type 'object' without properties.
835            if ( source === null ) return null;
836
837            // All non-objects use value semantics and don't need explict copying.       
838                if ( typeof source !== 'object' ) return source;
839
840            if( !depth || !(depth instanceof RecursionHelper) ) depth = new RecursionHelper(depth);
841
842            var cachedResult = depth.getCachedResult(source);
843
844            // we've already seen this object during this deep copy operation
845            // so can immediately return the result.  This preserves the cyclic
846            // reference structure and protects us from infinite recursion.
847            if ( cachedResult ) return cachedResult;
848
849            // objects may need special handling depending on their class.  There is
850            // a class of handlers call "DeepCopiers"  that know how to copy certain
851            // objects.  There is also a final, generic deep copier that can handle any object.
852            for ( var i=0; i<this.comparators.length; i++ ) {
853
854                    var comparator = this.comparators[i];
855
856                    if ( comparator.can(source) ) {
857       
858                            // once we've identified which DeepCopier to use, we need to call it in a very
859                            // particular order: create, cache, populate.  This is the key to detecting cycles.
860                            // We also keep track of recursion depth when calling the potentially recursive
861                            // populate(): this is a fail-fast to prevent an infinite loop from consuming all
862                            // available memory and crashing or slowing down the browser.
863     
864                            if( !result )
865                                // Start by creating a stub object that represents the copy.
866                                result = comparator.create(source);
867                            else if( !comparator.can(result) )
868                                throw new Error("can't compare diferent kind of objects.");
869
870                            // we now know the deep copy of source should always be result, so if we encounter
871                            // source again during this deep copy we can immediately use result instead of
872                            // descending into it recursively. 
873                            depth.cacheResult(source, result);
874
875                            // only DeepCopier.populate() can recursively deep copy.  So, to keep track
876                            // of recursion depth, we increment this shared counter before calling it,
877                            // and decrement it afterwards.
878                            depth.depth++;
879                            if ( depth.depth > depth.maxDepth ) {
880                                    throw new Error("Exceeded max recursion depth in deep copy.");
881                            }
882
883                            // It's now safe to let the comparator recursively deep copy its properties.
884                            var returned = comparator.populate( function(source, result) { return DataLayer.copy(source, result, depth); }, source, result );
885       
886                                if(returned)
887                                        result = returned;
888
889                            depth.depth--;
890
891                            return result;
892                    }
893            }
894            // the generic copier can handle anything, so we should never reach this line.
895            throw new Error("no DeepCopier is able to copy " + source);
896    },
897
898    // publicly expose the list of deepCopiers.
899    comparators: [],
900
901    // make deep copy() extensible by allowing others to
902    // register their own custom Comparators.
903    registerComparator: function(comparatorOptions) {
904
905          // publicly expose the Comparator class.
906          var comparator = {
907
908              // determines if this Comparator can handle the given object.
909              can: function(source) { return false; },
910   
911              // starts the deep copying process by creating the copy object.  You
912              // can initialize any properties you want, but you can't call recursively
913              // into the copy().
914              create: function(source) { },
915
916              // Completes the deep copy of the source object by populating any properties
917              // that need to be recursively deep copied.  You can do this by using the
918              // provided deepCopyAlgorithm instance's copy() method.  This will handle
919              // cyclic references for objects already deepCopied, including the source object
920              // itself.  The "result" passed in is the object returned from create().
921              populate: function(deepCopyAlgorithm, source, result) {}
922          };
923
924          for ( var key in comparatorOptions ) comparator[key] = comparatorOptions[key];
925
926          this.comparators.unshift( comparator );
927    },
928 
929    diff: function( base, toDiff ){
930
931        if( typeof base === 'undefined' || $.isEmptyObject(base) )
932            return( toDiff );
933
934        if( toDiff === false )
935            return( false );
936
937        toDiff = $.extend( {}, toDiff );
938
939        for( var key in toDiff )
940        {
941            switch( $.type(toDiff[key]) )
942            {
943              case 'object':
944                if( $.isEmptyObject(toDiff[key] = this.diff( base[key], toDiff[key] )) )
945                  delete toDiff[key];
946              break;
947              case 'array':
948                if( base[key] && !(toDiff[key] = $.grep( toDiff[key], function( el, i ){ return( $.inArray( el, base[key] ) === -1 ); } )).length )
949                  delete toDiff[key];
950              break;
951              default:
952                if( base[key] == toDiff[key] )
953                  delete toDiff[key];
954            }
955        }
956
957        return( toDiff );
958
959    },
960   
961    links: function( concept, reverse ){
962
963        if( !this.links[ concept ] )
964        {
965            var result = this.dispatch( "links", { concept: concept } ) || false;
966
967            if( !result )
968                return( false );
969
970            this.concepts[ concept ] = $.extend( this.concepts[ concept ] || {},
971                                                 result['concepts'] || {} );
972
973            this.links[ concept ] =  result['links'] || {};
974
975           this.nestedLinks[ concept ] = result['nestedLinks'] || {};
976        }
977
978        if( reverse )
979        {
980            return( this.nestedLinks[ concept ] );
981        }
982
983        return( this.links[ concept ] );
984
985    },
986   
987    isConcept: function( concept, attr ){
988     
989        if( typeof this.concepts[concept] === "undefined" )
990        {
991            this.links( concept );
992        }
993
994        return !!this.concepts[ concept ][ attr ];
995    },
996   
997    URI: function( concept, URI, context ){
998     
999        if( res = internalUrl.exec( concept ) )
1000            concept = res[1];
1001       
1002        context = context ? "(" + context + ")" : "";
1003     
1004        if( URI )
1005            return( concept + context + "://" + URI );
1006        else
1007            return( concept );
1008     
1009    },
1010   
1011    parseURI: function( URI ){
1012
1013        return internalUri.exec( URI ) || false;
1014
1015    },
1016   
1017   
1018   
1019   
1020    generateId: function( concept ){
1021     
1022        var newId = this.counter + "(javascript)";
1023     
1024        this.store( ":counter", (this.counter++) + "" );
1025       
1026        return( newId );
1027    },
1028   
1029
1030   
1031
1032    get: function( concept, /*URI, */filter, oneSide ){
1033
1034        ///////////////////////////// normalize ////////////////////////////////
1035        if( arguments.length == 2 && $.type(filter) === "boolean" )
1036        {
1037            oneSide = filter;
1038            filter = false;
1039        }
1040       
1041        var encoder = false, id = false, bothSides = (typeof oneSide === 'undefined'), res;
1042       
1043        if( $.type(filter) === "string" )
1044        {
1045            id = filter;
1046            filter = false;
1047        }
1048
1049        filter = filter || false;
1050
1051        if( !concept )
1052            return( false );
1053
1054        if( res = internalUrl.exec( concept ) )
1055        {
1056            encoder = concept;
1057            concept = res[1];
1058
1059            if( filter )
1060                filter = this.criteria( encoder, filter );
1061        }
1062       
1063        if ( $.type(filter) === "array" )
1064        {
1065            filter = { filter: filter, criteria: false };
1066        }
1067       
1068        //////////////////////////////////////////////////////////////////////////
1069       
1070        var result = false;
1071       
1072        if( bothSides || !oneSide )
1073            result = this.check( concept, id || filter );
1074       
1075        if (bothSides && filter.filter)
1076                result = false;
1077
1078               
1079        if( !result && (bothSides || oneSide) )
1080        {
1081            result = this.request( concept, id || filter.filter, filter.criteria );
1082
1083            if( result && bothSides && (!filter ||
1084                                        !filter.criteria ||
1085                                        !filter.criteria.format) )
1086            {
1087              var newResult = [];
1088           
1089              $.each( result, function( i, res ){
1090                        newResult[ i ] = $.extend( {}, res );
1091                  });
1092
1093              this.put( concept, id, newResult, false );
1094            }
1095        }
1096
1097        if( /*result &&*/ encoder )
1098            result = this.encode( encoder, result, filter ); //TODO: retirar o filtro no método encode
1099
1100        return( result );
1101    },
1102   
1103    filter: function( base, filter, criteria ){
1104     
1105        if( !$.isArray( filter || [] ) )
1106            filter = filter.filter || false;
1107
1108        if( !filter )
1109            return( base );
1110
1111        var filtered = [];
1112     
1113        for( var key in base )
1114            if( this.storage.filter( base[key], this.copy( filter ) ) )
1115                filtered[ filtered.length ] = key;
1116
1117        return( filtered );
1118    },
1119
1120        converterType: function( filter ){
1121
1122                        return isNaN(parseInt(filter)) ? filter : parseInt(filter);
1123               
1124        },
1125
1126   
1127    compare: function( operator, b, t ){
1128     
1129        var base = this.converterType(b);
1130        var test = this.converterType(t);
1131         
1132    switch( operator ){
1133       
1134        case '*':  return RegExp( ".*" + test + ".*" ).test( base );
1135        case '^':  return RegExp( "^" + test +  ".*" ).test( base );
1136        case '$':  return RegExp( ".*"  + test + "$" ).test( base );
1137
1138        case '&':  return ( base && test );
1139        case '|':  return ( base || test );
1140
1141        case '=':  return ( base == test );
1142        case '<=': return ( base <= test );
1143        case '>=': return ( base >= test );
1144        case '>':  return ( base <  test );
1145        case '<':  return ( base >  test );
1146       
1147        default: return false;
1148        }
1149     
1150    },
1151   
1152//     clone: function( object ){
1153//
1154//      new { prototype: object };
1155//
1156//     },
1157
1158    check: function( namespace, filter ){
1159
1160        if( !namespace )
1161            return( false );
1162
1163        var result = this.storage.get( namespace );
1164
1165        if( !filter || !result )
1166          return DataLayer.copy( result || false );
1167
1168        var keys = [];
1169
1170        if( notArray = $.type(filter) === "string" )
1171            keys = [ filter ];
1172        else if( $.type(filter) !== "array" )
1173                keys = this.filter( result, filter.filter, filter.criteria );
1174
1175        var res = [];
1176
1177        for( var i = 0; i < keys.length; i++ )
1178            res[ res.length ] = result[keys[i]];
1179
1180        return DataLayer.copy( notArray ? res[0] || false : res.length ? res : false );
1181    },
1182
1183    storage: {
1184     
1185        cache: {},
1186     
1187        set: function( key, value ){
1188
1189            this.cache[key] = value;
1190
1191        },
1192        get: function( key ){
1193
1194            return this.cache[key];
1195
1196        },
1197        del: function( key ){
1198
1199            delete this.cache[key];
1200
1201        },
1202       
1203        filter: function( base, filter ){
1204     
1205            var bool, op = filter.shift();
1206
1207            switch( op )
1208            {
1209                case 'IN':
1210                  for( var i = 0, f = []; i < filter[1].length || !(filter = f); i++ )
1211                      f[i] = [ '=', filter[0], filter[1][i] ];
1212                case 'OR':
1213                    op = '|';
1214                    bool = false;
1215                break;
1216                case 'AND':
1217                    op = '&';
1218                    bool = true;
1219                break;
1220                default : return DataLayer.compare( op, base[ filter[0] ], filter[1] );
1221            }
1222           
1223            for( var strict = bool;
1224
1225                filter.length && ( strict ? bool : !bool );
1226           
1227                bool = DataLayer.compare( op, bool, this.filter( base, filter.shift() ) ) );
1228
1229            return( bool );
1230        }
1231    },
1232
1233    flush: function(){
1234
1235    },
1236   
1237    restore: function(){
1238     
1239    },
1240
1241    store: function( namespace, key, data ){
1242
1243        if( !data )
1244          return this.storage.set( namespace, key );
1245
1246        var res = this.check( namespace ) || {};
1247
1248        res[key] = data;
1249
1250        return this.storage.set( namespace, res );
1251    },
1252
1253    del: function( namespace, key ){
1254     
1255        if( !key )
1256          return this.storage.del( namespace );
1257
1258        var res = this.check( namespace ) || {};
1259
1260        delete res[key];
1261
1262        return this.storage.set( namespace, res );
1263     
1264    },
1265   
1266     move: function( concept, oldId, newId ){
1267
1268        this.put( concept, newId, this.check( concept, oldId ), false );
1269
1270        this.remove( concept, oldId, false );
1271    },
1272   
1273
1274   
1275   
1276   
1277    request: function( concept, filter, criteria ){
1278
1279      var id = false, criteria = criteria || {};
1280
1281      if( $.type(filter) === "string" )
1282      {
1283          id = filter;
1284          filter = false;
1285      }
1286
1287      return this.dispatch( "request", {
1288
1289          concept: concept || '',
1290          id: id || '',
1291          filter: filter || '',
1292          criteria: criteria || '',
1293          service: criteria.service || '',
1294          properties: criteria.properties || ''
1295
1296      } );
1297    },
1298
1299   
1300    //         sync: function( data, callback ){
1301//
1302//      if( !data || $.isEmptyObject( data ) )
1303//          return;
1304//       
1305//      this.send( "Sync", data, function( data, status, jqXHR ){
1306//
1307// //       switch( status )
1308// //       {
1309// //         case "error":
1310// //         case "parsererror":
1311// //           return DataLayer.rollback( concept, URI );
1312// //         case "success":
1313// //           return DataLayer.commit();
1314// //         case "timeout":
1315// //         case "notmodified":
1316// //       }
1317//
1318//          if( callback )
1319//          {
1320//              var result = callback( data, status, jqXHR );
1321//
1322//              if( result === false )
1323//                  return;
1324//              else if( typeof result != "undefined" )
1325//                  data = result;
1326//          }
1327//
1328//          for( var URI in data )
1329//          {
1330//              var parsed = DataLayer.parseURI( URI ),
1331//   
1332//              concept = parsed[1], /*URI = parsed[3],*/
1333//
1334//              links = DataLayer.links( concept );
1335//
1336//              for( var linkName in links )
1337//              {
1338//                  var subURI = data[URI][linkName];
1339//
1340//                  if( subURI && data[subURI] )
1341//                  {
1342//                      data[URI][linkName] = DataLayer.put( linkName, subURI, data[subURI], false );
1343//
1344//                      delete( data[subURI] );
1345//                  }
1346//              }
1347//
1348//              DataLayer.put( concept, URI, data[URI], false );
1349//          }
1350//      }, true );
1351//
1352//     },
1353
1354//     report: function( concept, URI, data, sync )
1355//     {
1356//      var current = this.dequeue( 'current', concept, URI );
1357//
1358//      if( !current )
1359//          this.enqueue( 'current', concept, URI, ( current = this.check( concept, URI ) || {} ) );
1360//
1361//      var diff = this.diff( current, data );
1362//
1363//      if( !diff )
1364//          this.dequeue( 'current', concept, URI, true );
1365//      else
1366//          this.enqueue( 'diff', concept, URI, diff );
1367//     
1368//      if( sync )
1369//          this.commit( concept, URI, function(){
1370//
1371//              DataLayer.set( concept, URI, data, false );
1372//
1373//          });
1374//     },
1375   
1376//     enqueue: function( type, concept, URI, obj ){
1377//       
1378//      //var newURI = this.URI( concept, URI );
1379//     
1380//      if( !this.queue[type] )
1381//          this.queue[type] = {};
1382//
1383//      if( !this.queue['all'] )
1384//          this.queue['all'] = {};
1385//     
1386//      if( !this.queue[type][concept] )
1387//          this.queue[type][concept] = {};
1388//     
1389//      if( !this.queue['all'][type] )
1390//          this.queue['all'][type] = {};
1391//     
1392//      if( !this.queue['all'][type][/*new*/URI] )
1393//          this.queue[type][concept][URI] = this.queue['all'][type][/*new*/URI] = obj;
1394//
1395//      this.store( ':queue', this.queue );
1396//     },
1397//     
1398//     dequeue: function( type, concept, URI, remove ){
1399//       
1400//       ///////////////////////////// normalize ////////////////////////////////
1401//      if( arguments.length < 4 && $.type(URI) === 'boolean' )
1402//      {
1403//          remove = URI;
1404//          URI = false;
1405//      }
1406//      if( arguments.length < 3 && $.type(concept) === 'boolean' )
1407//      {
1408//          remove = concept;
1409//          concept = false;
1410//      }
1411//       //////////////////////////////////////////////////////////////////////////
1412//       
1413//      if( !this.queue[type] || !this.queue['all'] )
1414//          return( false );
1415//     
1416//      if( !concept )
1417//      {
1418//          var obj = this.queue['all'][type];
1419//         
1420//          if( remove )
1421//          {
1422//              delete this.queue['all'][type];
1423//              delete this.queue[type];
1424//          }
1425//
1426//          this.store( ':queue', this.queue );
1427//          return( obj );
1428//      }
1429//
1430//      if( !this.queue[type][concept] )
1431//          return( false );
1432//     
1433//      if( !URI )
1434//      {
1435//          var obj = this.queue[type][concept];
1436//
1437//          if( remove )
1438//          {
1439//              var URIs = this.queue[type][concept];
1440//
1441//              for( var subURI in URIs )
1442//                   delete this.queue['all'][type][subURI];
1443//
1444//              delete this.queue[type][concept];
1445//          }
1446//
1447//          this.store( ':queue', this.queue );
1448//          return( obj );
1449//      }
1450//
1451// //   var newURI = URI ? this.URI( concept, URI ) : concept;
1452//     
1453//      var obj = this.queue['all'][type][/*new*/URI];
1454//   
1455//      if( remove )
1456//      {
1457//          delete this.queue['all'][type][/*new*/URI];
1458//          delete this.queue[type][concept][URI];
1459//      }
1460//
1461//      this.store( ':queue', this.queue );
1462//      return( obj );
1463//     },
1464   
1465           //TODO: definir a 'usage' desta função e refatora-la
1466//     set: function( concept, filter, data, oneSide ){
1467//
1468//      ///////////////////////////// normalize ////////////////////////////////
1469//      if( arguments.length == 2 )
1470//      {
1471//          data = filter;
1472//          filter = false;
1473//      }
1474//      if( $.type(data) === "boolean" )
1475//      {
1476//          oneSide = data;
1477//          data = filter;
1478//          filter = false;
1479//      }
1480//     
1481//      if( !concept || !data )
1482//          return( false );
1483//
1484//      var decoder = "", URI = false, bothSides = (typeof oneSide === "undefined");
1485//     
1486//      if( $.type(filter) === "string" )
1487//      {
1488//          URI = filter;
1489//          filter = false;
1490//      }
1491//
1492//      if( res = internalUrl.exec( concept ) )
1493//      {
1494//          //TODO: verificar se a decodificaçao deve ser feita em cada item do array
1495//          data = this.decode( concept, data );
1496//          concept = res[1];
1497//          decoder = res[2];
1498//      }
1499//      ///////////////////////////////////////////////////////////////////////////
1500//
1501//      if( bothSides || oneSide )
1502//          this.report( concept, URI, data, !bothSides );
1503//
1504//      if( bothSides || !oneSide )
1505//      {
1506//          if( URI )
1507//          {
1508//            var helper = {};
1509//            helper[URI] = data;
1510//            data = helper;
1511//          }
1512//
1513//          for( var URI in data )
1514//          {
1515//              var current = this.check( concept, URI ) || {};
1516//
1517//              data[URI] = this.merge( current, data[URI] );
1518//
1519//              this.store( concept, URI, data[URI] );
1520//          }
1521//
1522//      }
1523//
1524//      this.broadcast( concept, oneSide ? 'client' : 'server' );
1525//
1526//      return( true );
1527//     },
1528//     put: function( concept, URI, data, oneSide ){
1529//       
1530//       ///////////////////////////// normalize ////////////////////////////////
1531//      if( $.type(URI) !== "string" && arguments.length < 4 )
1532//      {
1533//          oneSide = data;
1534//          data = URI;
1535//          URI = false;
1536//      }
1537//       ////////////////////////////////////////////////////////////////////////
1538//       
1539//       ////////////////////////////// linkage /////////////////////////////////
1540//      var result = false, links = this.links( concept );
1541//
1542//      for( var link in links )
1543//      {
1544//          if( data[link] )
1545//          {
1546//              if( $.isArray( data[link] ) )
1547//              {
1548//                  data[link] = this.put( links[link], data[link].URI, data[link], oneSide );
1549//              }
1550//              else if( $.isObject( data[link] ) )
1551//              {
1552//                  $.each( data[link], function( i, el ){
1553//
1554//                        data[link][i] = this.put( links[link], el.URI, el, oneSide );
1555//
1556//                  });
1557//              }
1558//          }
1559//      }
1560//       //////////////////////////////////////////////////////////////////////////
1561//     
1562//      if( typeof data.URI === "undefined" )
1563//      {
1564//          URI = this.add( concept, data, oneSide );
1565//      }
1566//      else if( data.URI === false )
1567//      {
1568//          status = this.remove( concept, URI, oneSide );
1569//      }
1570//      else
1571//      {
1572//          status = this.set( concept, URI, data, oneSide );
1573//      }
1574//
1575//      if( URI && data.URI && URI !== data.URI )
1576//          this.move( concept, URI, data.URI );
1577//
1578//      return( data.URI || URI );
1579//
1580//     },
1581   
1582    //     add: function( concept, data, oneSide ){
1583//       
1584//       ///////////////////////////// normalize ////////////////////////////////
1585//      if( !concept || !data )
1586//          return( false );
1587//
1588//      if( res = internalUrl.exec( concept ) )
1589//      {
1590//          //TODO: verificar se a decodificaᅵᅵo deve ser feita em cada item do array
1591//          data = this.decode( concept, data );
1592//          concept = res[1];
1593//          decoder = res[2];
1594//      }
1595//
1596//      var bothSides = (typeof oneSide === "undefined"), uris = [];
1597//
1598//      if( notArray = $.type(data) !== "array" )
1599//          data = [ data ];
1600//       //////////////////////////////////////////////////////////////////////////
1601//
1602//      for( var i = 0; i < data.length; i++ )
1603//      {
1604//          var URI = uris[i] = this.generateURI( concept );
1605//
1606//          this.set( concept, URI, data[i], oneSide );
1607//      }
1608//
1609//      return( notArray ? uris[0] : uris );
1610//     },
1611//      put: function( concept, data ){
1612//
1613//      var decoder = "";
1614//
1615//      if( res = internalUrl.exec( concept ) )
1616//      {
1617//          data = this.decode( concept, data );
1618//          concept = res[1];
1619//          decoder = res[2];
1620//      }
1621//
1622//      var New = [], Update = [], uris = [];
1623//
1624//      if( notArray = $.type(data) !== "array" )
1625//          data = [ data ];
1626//     
1627//      for( var i = 0; i < data.length; i++ )
1628//      {
1629//          if( !data[i].URI )
1630//          {
1631//              uris[ uris.length ] = data[i].URI = this.create( concept, data[i] );
1632//              New[ New.length ] = data[i];
1633//              continue;
1634//          }
1635//
1636//          for( var key in data[i] )
1637//              if( klass = this.isReference( concept, key, data[i][key] ) )
1638//                    data[i][key] = this.put( klass + decoder, data[i][key] );
1639//
1640//          Update[ Update.length ] = this.update( concept, data[i].URI, data[i] );
1641//      }
1642//
1643//      this.report( concept, { "created": New, "updated": Update });
1644//
1645//      return( notArray ? uris[0] : uris );
1646//     },
1647//     merge: function( concept, current, data ){
1648//
1649//      current = current || {};
1650//
1651//      for( var key in data )
1652//          current[key] = (klass = this.isReference( concept, key, data[key] )) ?
1653//                         this.merge( klass, current[key], data[key] ) : data[key];
1654//
1655//      return( current );
1656//     },
1657//
1658//     isReference: function( concept, key, value ){
1659//
1660//       return( ($.type(value) === "object" ||
1661//             $.type(value) === "array" )? this.links[concept][key] : false );
1662//
1663//     },
1664//     
1665//     set: function( concept, data, URI, mergeable ){
1666//     
1667//      if( URI )
1668//      {
1669//          var res = this.get( concept, true ) || {};
1670//         
1671//          if( mergeable )
1672//              data = this.merge( res[URI] || {}, data );
1673//
1674//          res[URI] = data;
1675//
1676//          data = res;
1677//      }
1678//
1679//      return this.store( concept, data );
1680//     },   
1681//
1682//     create: function( concept, data ){
1683//
1684//       if( notArray = ($.type(data) !== "array") )
1685//          data = [ data ];
1686//
1687//       var uris = [];
1688//
1689//       for( var i = 0; i < data.length; i++ )
1690//       {
1691//        uris[ uris.length ] = data[i].URI = "javascript://" + (this.counter + i);
1692//
1693//        this.set( concept, data[i], data[i].URI );
1694//       }
1695// 
1696//       this.set( ":counter", (this.counter += data.length) );
1697//
1698//       return notArray ? uris[0] : uris;
1699//     },
1700//
1701//     update: function( concept, URI, data )
1702//     {
1703//      var target = this.check( concept, URI ) || {};
1704//
1705//      target = this.merge( concept, target, data );
1706//
1707//      if( target.URI !== URI )
1708//          this.remove( concept, URI );
1709//
1710//      this.set( concept, target, target.URI );
1711//
1712//      return( target );
1713//     },
1714//
1715//     remove: function( concept, URI ){
1716//
1717//      if( !URI )
1718//          return this.storage.del( concept );
1719//
1720//      var res = this.check( concept );
1721//
1722//      delete res[URI];
1723//     
1724//      this.set( concept, res );
1725//     },
1726//
1727//     del: function( concept, URI ){
1728//
1729//      this.remove( concept, URI );
1730//
1731//      this.report( concept, { "deleted": { 'URI': URI } });
1732//     },
1733//
1734//     report: function( concept, changes ){
1735//
1736//       this.broadcast( concept, changes.created, changes.updated, changes.deleted );
1737//
1738//      if( changes.created )
1739//          this.sync( concept, changes.created, 'create' );
1740//      if( changes.updated )
1741//          this.sync( concept, changes.updated, 'update' );
1742//      if( changes.deleted )
1743//          this.sync( concept, changes.deleted, 'delete' );
1744//
1745//     },
1746//
1747//
1748//    sync: function( concept, data, type ){
1749//
1750//      if( $.type(data) !== "array" )
1751//          data = [ data ];
1752//
1753//      $.each( data, function( i, el ){
1754//
1755//         DataLayer.send( concept, el, type );
1756//
1757//      });
1758//
1759//     },
1760//     
1761//     
1762//     
1763//     
1764//
1765//     request: function( concept, URI, filter ){
1766//
1767// //       if( startsDoubleDot.test(concept) )
1768// //     return( false );
1769//
1770//       filter = filter || {};
1771//
1772//       if( URI )
1773//      filter.URI = URI;
1774//
1775//       return this.send( concept, filter, "read", true );
1776//
1777//     },
1778//
1779//     send: function( concept, data, type, wait ){
1780//
1781//       switch( type )
1782//       {
1783//      case "create": type = "POST"; break;
1784//      case "update": type = "PUT"; break;
1785//      case "delete": type = "DELETE"; break;
1786//      case "read": type = "GET"; break;
1787//       }
1788//
1789//       var url = this.basePath + concept;
1790//
1791//       var result = [], notArray = false;
1792//
1793// //      alert( data.URI );
1794//
1795//       if( data.URI && data.URI.indexOf("javascript://") !== 0 )
1796//        url += "/" + data.URI;
1797//
1798//       var callback = function( dt, textStatus, jqXHR ){
1799//
1800//          if( notArray = (!$.isArray( dt )) )
1801//              dt = [ dt ];
1802//
1803//          $.each( dt, function( i, el ){
1804//
1805//              if( !el || !el.URI )
1806//                  return;
1807//
1808//              if( data.URI )
1809//                  el = DataLayer.update( concept, data.URI, el );
1810//              else
1811//                  DataLayer.set( concept, el, el.URI );
1812//
1813//              result[ result.length ] = el;
1814//              DataLayer.broadcast( concept );
1815//        });
1816//       };
1817//
1818//       $.ajax({
1819//            'async': ( !wait ),
1820//            'url': url,
1821//            'type': type,
1822//            'success': callback,
1823//            'dataType': 'json',
1824//            'data': data/*,
1825//            'processData': false*/
1826//        });
1827//
1828//       return( notArray ? result[0] || false : result );
1829//     },
1830   
1831   
1832    generateURI: function( concept ){
1833     
1834        return this.URI( concept, this.generateId( concept ), "javascript" );
1835
1836    },
1837   
1838
1839    broadcast: function( concept, status, diff ){
1840
1841        if( this.listeners[ concept ] )
1842            for( var i = 0;
1843                i < this.listeners[ concept ].length;
1844                this.listeners[ concept ][ i++ ]( status, diff ) );
1845    },
1846
1847    listen: function( concept, listener ){
1848
1849        this.register( "listeners", concept, listener );
1850
1851    },
1852
1853    codec: function( concept, namespace, codec ){
1854
1855        if( codec.encoder )
1856            this.encoder( concept, namespace, codec.encoder );
1857        if( codec.decoder )
1858            this.decoder( concept, namespace, codec.decoder );
1859        if( codec.criteria )
1860            this.register( "criterias", concept + ":" + namespace, codec.criteria );
1861
1862    },
1863
1864    encoder: function( concept, namespace, encoder ){
1865
1866        this.register( "encoders", concept + ":" + namespace, encoder );
1867
1868    },
1869
1870    encode: function( encoder, data, filter ){
1871
1872        if( this.encoders[ encoder ] )
1873            for( var i = 0;
1874                i < this.encoders[ encoder ].length;
1875                data = this.encoders[ encoder ][ i++ ]( data, filter ) );
1876
1877        return( data );
1878    },
1879
1880    decoder: function( concept, namespace, decoder ){
1881
1882        this.register( "decoders", concept + ":" + namespace, decoder );
1883
1884    },
1885
1886    decode: function( decoder, data ){
1887
1888        if( this.decoders[ decoder ] )
1889            for( var i = 0;
1890                i < this.decoders[ decoder ].length;
1891                data = this.decoders[ decoder ][ i++ ]( data ) );
1892
1893        return( data );
1894    },
1895
1896    criteria: function( codec, filter ){
1897
1898        if( this.criterias[ codec ] )
1899            for( var i = 0;
1900                i < this.criterias[ codec ].length;
1901                filter = this.criterias[ codec ][ i++ ]( filter ) );
1902
1903        return( filter );
1904
1905    },
1906
1907    register: function( kind, concept, deployable ){
1908
1909      if( arguments.length < 3 )
1910      {
1911          deployable = concept;
1912          concept = kind;
1913          kind = 'global';
1914      }
1915
1916      if( !this[ kind ][ concept ] )
1917            this[ kind ][ concept ] = [];
1918
1919        this[ kind ][ concept ][ this[ kind ][ concept ].length ] = deployable;
1920
1921    },
1922   
1923    start: function(){
1924
1925        var timer = function(){
1926
1927              setTimeout( timer, 1 );
1928
1929              var now = parseInt( $.now() / 1000 );
1930
1931              var tasks = DataLayer.tasks[ now ];
1932
1933              if( !tasks ) return;
1934
1935              for( var i = 0; i < tasks.length; i++ )
1936              {
1937                  var result = tasks[i].task( now );
1938
1939                  if( tasks[i].factor )
1940                  DataLayer.schedule( tasks[i].task, tasks[i].factor );
1941              }
1942     
1943              delete DataLayer.tasks[ now ];
1944        };
1945
1946        setTimeout( timer, 1 );
1947    },
1948   
1949    task: function( timestamp, task, factor )
1950    {
1951        if( !this.tasks[ timestamp ] )
1952            this.tasks[ timestamp ] = [];
1953
1954        this.tasks[ timestamp ][ this.tasks[ timestamp ].length ] = { task: task, factor: factor || false };
1955    },
1956
1957    schedule: function( task, time ){
1958
1959        time = time || 1;
1960       
1961        var index = parseInt( $.now() / 1000 ) + time;
1962
1963        this.task( index, task, time );
1964    },
1965   
1966    poll: function( concept, time ){
1967     
1968      this.schedule( function( now ){
1969 
1970          DataLayer.commit( concept );
1971
1972        }, time || 5 );
1973    },
1974   
1975    init: function(){
1976     
1977        this.counter = parseInt( this.get( ":counter", false ) ) || 0;
1978
1979        if( !this.dispatchPath )
1980            this.dispatchPath = "../../";
1981
1982        if( !this.templatePath )
1983            this.templatePath = "";
1984
1985        if( !this.basePath )
1986            this.basePath = this.dispatchPath + "REST.php?q=";
1987
1988        this.schedule( function( now ){
1989
1990            DataLayer.flush();
1991
1992        });
1993
1994        this.start();
1995    }
1996}
1997
1998// the re-usable constructor function used by clone().
1999function Clone() {}
2000
2001//Recursion Helper
2002function RecursionHelper(){ this.clear(); };
2003
2004RecursionHelper.prototype = {
2005 
2006        constructor: RecursionHelper,
2007
2008        // copiedObjects keeps track of objects already copied by this
2009        // deepCopy operation, so we can correctly handle cyclic references.
2010        copiedObjects: [],
2011
2012        depth: 0,
2013
2014        maxDepth: 256,
2015
2016        //reset the recursion helper cache
2017        clear: function(){
2018                this.copiedObjects = [];
2019                this.depth = 0;
2020        },
2021
2022        // add an object to the cache.  No attempt is made to filter duplicates;
2023        // we always check getCachedResult() before calling it.
2024        cacheResult: function(source, result) {
2025                this.copiedObjects.push([source, result]);
2026        },
2027
2028        // Returns the cached copy of a given object, or undefined if it's an
2029        // object we haven't seen before.
2030        getCachedResult: function(source) {
2031
2032                for ( var i=0; i<this.copiedObjects.length; i++ ) {
2033                        if ( this.copiedObjects[i][0] === source ) {
2034                                return this.copiedObjects[i][1];
2035                        }
2036                }
2037
2038                return undefined;
2039        }
2040};
2041
2042// Generic Object copier
2043// the ultimate fallback DeepCopier, which tries to handle the generic case.  This
2044// should work for base Objects and many user-defined classes.
2045DataLayer.registerComparator({
2046        can: function(source) { return true; },
2047
2048        create: function(source) {
2049                if ( source instanceof source.constructor ) {
2050                        return DataLayer.clone(source.constructor.prototype);
2051                } else {
2052                        return {};
2053                }
2054        },
2055
2056        populate: function(deepCopy, source, result) {
2057                for ( var key in source ) {
2058                        if ( source.hasOwnProperty(key) ) {
2059                                result[key] = deepCopy(source[key], result[key]);
2060                        }
2061                }
2062                return result;
2063        }
2064});
2065
2066// Array copier
2067DataLayer.registerComparator({
2068        can: function(source) {
2069                return ( source instanceof Array );
2070        },
2071
2072        create: function(source) {
2073                return new source.constructor();
2074        },
2075
2076        populate: function(deepCopy, source, result) {
2077                for ( var i=0; i<source.length; i++) {
2078                        result.push( deepCopy(source[i], result[i]) );
2079                }
2080                result =  DataLayer.unique( result )
2081                return result;
2082        }
2083});
2084
2085// Date copier
2086DataLayer.registerComparator({
2087        can: function(source) {
2088                return ( source instanceof Date );
2089        },
2090
2091        create: function(source) {
2092                return new Date(source);
2093        }
2094});
2095
2096// HTML DOM Node copier
2097DataLayer.registerComparator({
2098
2099        // function to detect Nodes.  In particular, we're looking
2100        // for the cloneNode method.  The global document is also defined to
2101        // be a Node, but is a special case in many ways.
2102        can: function(source) {
2103         
2104          if ( window.Node ) {
2105                  return source instanceof Node;
2106          } else {
2107                  // the document is a special Node and doesn't have many of
2108                  // the common properties so we use an identity check instead.
2109                  if ( source === document ) return true;
2110                  return (
2111                          typeof source.nodeType === 'number' &&
2112                          source.attributes &&
2113                          source.childNodes &&
2114                          source.cloneNode
2115                  );
2116          }
2117      },
2118
2119      create: function(source) {
2120              // there can only be one (document).
2121              if ( source === document ) return document;
2122
2123              // start with a shallow copy.  We'll handle the deep copy of
2124              // its children ourselves.
2125              return source.cloneNode(false);
2126      },
2127     
2128      diff: function(base, source){
2129       
2130      },
2131
2132      populate: function(deepCopy, source, result) {
2133              // we're not copying the global document, so don't have to populate it either.
2134              if ( source === document ) return document;
2135
2136              // if this Node has children, deep copy them one-by-one.
2137              if ( source.childNodes && source.childNodes.length ) {
2138                      for ( var i=0; i<source.childNodes.length; i++ ) {
2139                              var childCopy = deepCopy(source.childNodes[i], result.childNodes[i] || false );
2140                              result.appendChild(childCopy);
2141                      }
2142              }
2143                return result;
2144      }
2145});
2146
2147DataLayer.init();
2148
2149// setTimeout(function(){
2150// 
2151//     
2152//
2153// }, 1000 );
2154
2155// var DataLayer = {
2156//
2157//     get: function( concept, filter ){
2158//
2159//      var data = this.storage.get( concept );
2160//
2161//      if( !filter )
2162//          return( data );
2163//
2164//      return this.filter( data, filter );
2165//     },
2166//     
2167//     filter:function( data, filter ){
2168//       
2169//      if( filter.charAt )
2170//          filter = { URI: filter };
2171//     
2172//      var filtered = [];
2173//
2174//      $.each(data, function(i, obj){
2175//       
2176//          for( var attr in filter )
2177//              if( filter[attr] !== obj[attr] )
2178//                  return( true );
2179//
2180//          filtered[i] = obj;
2181//      });
2182//
2183//      return( filtered );
2184//     },
2185//
2186//     find: function( concept, filter, callback ){
2187//
2188//      var data = this.get( concept, filter );
2189//
2190//      if( data )
2191//          return callback( data );
2192//
2193//      //TODO: register callback like a weak listener
2194//
2195// //   $.ajax({
2196// //         type: 'GET',
2197// //         data: $.param( filter ),
2198// //         success: callback, 
2199// //         url: BASE_PATH + filter.URI || concept
2200// //   });
2201//      this.report( concept, filter );
2202//     },
2203//
2204//     put: function( concept, data, filter ){
2205//
2206//      var beforeDiff = this.store( concept, $.extend({},data) );
2207//
2208//      this.report( concept, data, filter, beforeDiff );
2209//     },
2210//     
2211//     
2212//     /*var data = {
2213//                      startTime: $.now(),
2214//                      endTime: $.now() + 1800000,
2215//                      summary: "meu querido evento",
2216//                      description: "desc do evento",
2217//                      location: "prognus software livre",
2218//                      class: 1,
2219//                      calendar: 1,
2220//                      category: 1,
2221//                      participants: [ {
2222//                                         user: { isExternal: true, mail: "user7@prognus.org", name: "user7" }
2223//                                    },{
2224//                                         user: "1003"
2225//                                    } ]
2226//
2227//                };*/
2228//     
2229//
2230//     merge:function( data, target ){
2231//       
2232//      var diff = { New: {}, Update:{}, Delete: {} };
2233//       
2234//      for( var key in data )
2235//      {
2236//          if( !target[ key ] )
2237//              diff.New[ key ] = target[ key ] = data[ key ];
2238//
2239//         
2240//       
2241//      }
2242//       
2243//     }
2244//
2245//     store: function( concept, data, filter ){
2246//
2247//      if( !data.spline )
2248//          data = [ data ];
2249//
2250//      var target = this.storage.get( concept );
2251//     
2252//      var diff = { New: {}, Update:{}, Delete: {} };
2253//
2254//      for( var i = 0; i < data.length; i++ )
2255//      {
2256//          if( data[i].URI && target[ data[i].URI ] )
2257//          {
2258//              diff.Update[ data[i].URI ] = this.merge( target[ data[i].URI ], data[i] );
2259//          }
2260//          else
2261//          {
2262//              diff.New[] = data[i];
2263//          }
2264//      }
2265//
2266//     
2267//
2268//      this.broadcast( concept, data );
2269//
2270//      if( filter )
2271//          target = this.filter( target, filter );
2272//
2273//      if( target )
2274//          data = $.extend( target, data );
2275//
2276//      this.storage.set( concept, data );
2277//
2278// //   return;
2279//     },
2280//     
2281//     set: function( concept, data, filter ){
2282//
2283//       
2284//
2285//     },
2286//
2287//     post: function( concept, data, filter, isNew ){
2288//
2289//      var callback = function(  ){ DataLayer.store( concept, data, filter ) };
2290//
2291//      //TODO: register callback like a weak listener
2292//
2293//      this.report( concept, data, filter, isNew );
2294//     },
2295//     
2296//     report: function( concept, filter, postData, isNew ){
2297//       
2298//      $.ajax({
2299//              type: postData ? isNew ? 'POST' : 'PUT' : 'GET',
2300//              data: postData || $.param( filter ),
2301//              success: function( data ){ DataLayer.broadcast( concept ) },
2302//              url: BASE_PATH + filter.URI || concept
2303//        });
2304//     },
2305//     
2306//     del:function( concept, filter ){
2307//
2308//       
2309//
2310//     }
2311//     
2312//     broadcast: function( concept, data ){
2313//
2314//     
2315//
2316//     },
2317//
2318//     pool: function(){
2319//       
2320//     },
2321//
2322//     refresh: function(){
2323//       
2324//     }
2325// };
2326
2327//
2328// DataLayer = {
2329//   
2330//     get: function( concept, filter ){
2331//
2332//      var data = this.storage.get( concept );
2333//
2334//      if( !filter )
2335//          return( data );
2336//
2337//      if( filter.charAt )
2338//          filter = { URI: filter };
2339//     
2340//      var filtered = [];
2341//
2342//      $.each(data, function(i, obj){
2343//       
2344//          for( var attr in filter )
2345//              if( filter[attr] !== obj[attr] )
2346//                  return( true );
2347//
2348//          filtered[i] = obj;
2349//      });
2350//
2351//      return( filtered );
2352//     },
2353//
2354//     find: function( concept, filter, callback ){
2355//
2356//      var data = this.get( concept, filter );
2357//
2358//      if( data )
2359//          return callback( data );
2360//
2361//       $.ajax({
2362//            type: 'GET',
2363//            data: $.param( filter ),
2364//            success: callback, 
2365//            url: filter.URI || concept
2366//      });
2367//     },
2368//
2369//     put: function( concept, data, filter ){
2370//
2371//      var target = this.get( concept, filter );
2372//
2373//      if( target )
2374//          data = $.extend( target, data );
2375//       
2376//      this.storage.set( concept, data );
2377//     
2378//      //diff
2379//     },
2380//     
2381//     post: function( concept, data, filter ){
2382//
2383//     
2384//
2385//     },
2386//     
2387//     pool: function(){
2388//       
2389//     },
2390//     
2391//     queue: function(){
2392//       
2393//     },
2394//     
2395//     dequeue: function(){
2396//       
2397//     },
2398//     
2399//     refresh: function(){
2400//       
2401//     }
2402// }
2403
2404// var DataLayer = {
2405 
2406//       cache: {},
2407 
2408//       get: function( concept, location ){
2409       
2410           /* if( location )
2411            {*/
2412//              var schema = $.data( this.cache, concept + ':schema' );
2413//              var uri = [];
2414//
2415//              $.each( schema, function( i, addrs ){
2416//                    uri[ uri.length ] = location[addrs];
2417//              });
2418
2419                /*var filter = [], result = false;
2420
2421                while( !(result = $.data( this.cache, uri.join( '.' ) )) || !(uri = uri.join('.')) )
2422                  filter[ filter.length ] = uri.pop();
2423 
2424                if( !filter.length )
2425                {
2426                    var indexes = $.data( this.cache, uri + ':indexes' );
2427
2428                    if( indexes )
2429                        Array.prototype.concat.apply( result, indexes );
2430                   
2431                    return( result );
2432                }
2433
2434                for( var i = 0; i < result.length; i++ )
2435                {
2436                   
2437                }
2438
2439                if( result.length )
2440                    return( result );
2441            }*/
2442
2443//          var data = $.data( this.cache, concept );
2444
2445//          if( !data )
2446//              $.ajax( );
2447
2448//          return( data );
2449//       },
2450     
2451//       data: function(){
2452//
2453//       
2454//
2455//       }
2456//       
2457//       search: function( concept, filter ){
2458//
2459//        var schema = $.data( this.cache, concept + ':schema' );
2460//        var uri = [];
2461//
2462//        $.each( schema, function( i, addrs ){
2463//              uri[ uri.length ] = location[addrs];
2464//        });
2465//       }
2466//       put: function( concept, data, location ){
2467
2468//          if( location )
2469//          {
2470//              var schema = $.data( this.cache, concept + ':schema');
2471//              var uri = [];
2472
2473//              $.each( schema, function( i, addrs ){
2474//                    uri[ uri.length ] = location[addrs];
2475//              });
2476
2477//              var result = false, filter = [];
2478
2479//              while( !(result = $.data( this.cache, uri.join('.')) )
2480//                  filter[ filter.length ] = uri.pop();
2481
2482//              $.data( this.cache, '
2483
2484//          }
2485
2486//              var model = this.storage.get( concept );
2487//
2488//              $.each( model, function( i, o ){
2489//                  $.each( location, function( ii, attr ){
2490//                       if( o[ii] === attr )
2491//                          return( false );
2492//                  });
2493//              });
2494
2495//          return $.data( this.cache, concept, data );
2496
2497//       },
2498//       del: function( concept, location ){
2499//
2500//          if( location )
2501//          {
2502//              var schema = $.data( this.cache, 'concepts', concept );
2503//              var uri = [];
2504//
2505//              $.each( schema, function( i, addrs ){
2506//                    uri[ uri.length ] = location[addrs];
2507//              });
2508//
2509//              concept = uri.join( '.' );
2510
2511//              var model = this.storage.get( concept );
2512//
2513//              $.each( model, function( i, o ){
2514//                  $.each( location, function( ii, attr ){
2515//                       if( o[ii] === attr )
2516//                          return( false );
2517//                  });
2518//              });
2519//          }
2520//         
2521//     
2522//          $.removeData( this.cache, concept );
2523//       }
2524// }
2525
2526// internalUrl = /^([A-z0-9-_]+)(:[A-z0-9-_]+)?$/;
2527// internalUri = /^([a-zA-Z0-9-_]+)\(([a-zA-Z0-9-_]+)\):\/\/(.*)|([a-zA-Z0-9-_]+):\/\/(.*)$/;
2528// isGeneratedId = /^\d+\(javascript\)$/;
2529// arrayName = /^([A-z0-9-_]+)\[\]$/;
2530// startsDoubleDot = /^:/;
2531// FILE = 'files';
2532// // cached_urls = {};
2533//
2534// $.ajaxPrefilter(function( options, originalOptions, jqXHR ){
2535//
2536//       if( options.url != 'undefined' && internalUrl.test( options.url ) ){
2537//
2538// //     if( !cached_urls[options.url] )
2539// //         return;
2540// //     alert( options.url + " dentro" );
2541//        jqXHR.abort();
2542//
2543//        var callback = ( options.success || options.complete || $.noop );
2544//
2545//        switch( options.type.toUpperCase() )
2546//        {
2547//          case 'GET':
2548//                return callback( DataLayer.get( options.url, /*false,*/ options.data ) );
2549//
2550//          case 'POST':
2551//                return callback( DataLayer.put( options.url, options.data ) );
2552//        }
2553//
2554//        //return( false );
2555//
2556// //     options.url = params[1];
2557// //     options.data = ( options.data || "" ) + "&" + params[2];
2558//       }
2559//
2560// });
2561//
2562// // $("a").live("click", function( event ){
2563// //
2564// //     event.preventDefault();
2565// //
2566// //     $.ajax({
2567// //
2568// //   
2569// //
2570// //     });
2571// //
2572// // });
2573//
2574// $("form").live( "submit", function( event ){
2575//
2576//     var $this = $(this), action = $this.attr('action'), res = false,
2577//     
2578//     method = $this.attr( 'method' ),
2579//     
2580//     fileInputs = $this.find('input[type="file"]');
2581//     
2582//     if( fileInputs.length && !$this.is('[enctype="multipart/form-data"]') )
2583//     {
2584//      event.preventDefault();
2585//     
2586//      var formData = $this.serializeArray(), callback = DataLayer.receive;
2587//       
2588//      if( res = internalUrl.exec( action ) )
2589//      {
2590//          var data = {}, action = res[1];
2591//
2592//          data[action] = DataLayer.form( this, fileInputs );
2593//
2594//          formData = DataLayer.serializeForm( data );
2595//             
2596//              action = DataLayer.dispatchPath + 'post.php';
2597//          callback = $.noop;
2598//      }
2599//
2600//      DataLayer.send( action,
2601//                      [ method, 'iframe json' ], {},
2602//                      //TODO: check the type for conversion
2603//                      callback,
2604//                      false, { 'formData': formData,  'fileInput': fileInputs, 'paramName': FILE + '[]' } );
2605//
2606//      return( false );
2607//     }
2608//     
2609//     if( res = internalUrl.exec( action ) )
2610//     {
2611//      event.preventDefault();
2612//
2613//      var data = DataLayer.form( this );
2614//     
2615//      switch( method.toUpperCase() )
2616//      {
2617//        case 'GET':
2618//              DataLayer.get( res[0], data );
2619//
2620//        case 'POST':
2621//              DataLayer.put( res[1], data );
2622//      }
2623//
2624//      return( false );
2625//     }
2626//
2627//     return( true );
2628// });
2629//
2630// this.storage = new $.store();
2631//
2632// DataLayer = {
2633//
2634//     links: {},
2635//     concepts: {},
2636//     listeners: {},
2637//     encoders: {},
2638//     decoders: {},
2639//     templates: {},
2640//     criterias: {},
2641//     tasks: [],
2642//
2643//     render: function( templateName, data, filter, formatter, force ){
2644//
2645//      if( $.isFunction( filter ) )
2646//      {
2647//          force = formatter;
2648//          formatter = filter;
2649//          filter = false;
2650//      }
2651//
2652//      if( typeof data === "string" )
2653//      {
2654//          data = this.get( data, filter, force ) || {};
2655//      }
2656//     
2657//      var formatting = function( template ){
2658//
2659//            if( template === false ) return( false );
2660//
2661//            if( template )
2662//                DataLayer.templates[ templateName ] = new EJS({ text: template, cache: false });
2663//
2664//            var html = DataLayer.templates[ templateName ].render( { data: data } );
2665//
2666//            if( !formatter )
2667//                return( html );
2668//
2669//            return formatter( html );
2670//      }
2671//
2672//      if( this.templates[ templateName ] )
2673//      {
2674//          return formatting();
2675//      }
2676//
2677//      return this.send( DataLayer.templatePath + templateName, 'get', false, formatting, !!!formatter );
2678//     },
2679//     
2680//     send: function( url, type, data, callback, sync, extraOptions ){
2681//       
2682//        var result = false, fired = false;
2683//       
2684//        var envelope = {
2685//
2686//            'async': ( typeof sync !== "undefined" ? !sync : !!callback ),
2687//            'url': url,
2688//            'success': function( dt, textStatus, jqXHR ){
2689//
2690//                  if( callback )
2691//                  {
2692//                      fired = true;
2693//                      result = callback( dt, textStatus, jqXHR );
2694//                  }
2695//                  else
2696//                      result = dt;
2697//
2698//              },
2699//            'complete': function( jqXHR, textStatus ){
2700//
2701//                if( !fired && callback )
2702//                    result = callback( false, textStatus, jqXHR );
2703//
2704//            },
2705//
2706//            'type': $.isArray( type ) ? type[0] : type,
2707//            'data': data
2708//
2709//          };
2710//
2711//        if( $.isArray( type ) && type[1] )
2712//            envelope['dataType'] = type[1];
2713//
2714//        if( extraOptions )
2715//            envelope = $.extend( envelope, extraOptions );
2716//
2717//        $.ajax( envelope );
2718//       
2719//        return( result );
2720//     },
2721//     
2722//     dispatch: function( dispatcher, data, callback, isPost, dataType ){
2723//       
2724//       return this.send( this.dispatchPath + dispatcher + ".php",
2725//                      [ ( isPost ? 'post' : 'get' ), dataType || 'json' ],
2726//                      data,
2727//                      callback );
2728//
2729// //       $.ajax({
2730// //         'async': !!callback,
2731// //         'url': this.dispatchPath + dispatcher + ".php",
2732// //         'type': ( isPost ? 'post' : 'get' ),
2733// //         'dataType': 'json',
2734// //         'data': data,
2735// //         'success': function( dt, textStatus, jqXHR ){
2736// //
2737// //               if( callback )
2738// //               {
2739// //                   fired = true;
2740// //                   callback( dt, textStatus, jqXHR );
2741// //               }
2742// //               else
2743// //                   result = dt;
2744// //
2745// //           },
2746// //         'complete': function( jqXHR, textStatus ){
2747// //
2748// //             if( !fired && callback )
2749// //                 callback( false, textStatus, jqXHR );
2750// //
2751// //         }/*,
2752// //         'processData': false*/
2753// //     });
2754//
2755//       //return( result );
2756//     },
2757//
2758//     form: function( target, fileInputs ){
2759//
2760//      var params = {}, $this = $(target), inputArray = $this.serializeArray();
2761//
2762//      if( !$this.is( "form" ) )
2763//          $this = $this.parents( "form" );
2764//             
2765//      if( fileInputs )
2766//              fileInputs.each( function( i, el ){
2767//
2768//            inputArray[ inputArray.length ] = { name: $(this).prop("name"), value: FILE + i };
2769//
2770//              });
2771//
2772//      $.each( inputArray, function( i, el ){
2773//
2774//          if( newName = arrayName.exec( el.name ) )
2775//              el.name = newName[1];
2776//          else if( !params[ el.name ] )
2777//              return( params[ el.name ] = el.value );
2778//
2779//          params[ el.name ] = params[ el.name ] || [];
2780//
2781//          if( $.type(params[ el.name ]) !== "array" )
2782//              params[ el.name ] = [ params[ el.name ] ];
2783//
2784//          params[ el.name ].push( el.value );
2785//      });
2786//
2787// //   alert(dump(params));
2788//
2789//      return this.decode( $this.attr( "action" ), params );
2790//     },
2791//     
2792//      serializeForm: function( data, level ){
2793//     
2794//              var formData = [];
2795//     
2796//              for( key in data )
2797//              {
2798//                      var value = data[key];
2799//
2800//                      if( level !== undefined )
2801//                              key = level+'['+key+']';
2802//
2803//                      if( $.isArray(value) || $.isPlainObject(value) )
2804//                              formData = formData.concat( this.serializeForm( value, key ) );
2805//                      else
2806//                              formData[ formData.length ] = { name: key, value: value };
2807//              }
2808//             
2809//              return( formData );
2810//      },
2811//
2812//     blend: function( action, data ){
2813//
2814// //   if( notArray = (!$.isArray(data)) )
2815// //       data = [ data ];
2816//
2817//      var form = $('form[action="'+action+'"]');
2818//
2819//      form.get(0).reset();
2820//
2821//      var named = form.find( 'input[name]' );
2822//
2823//      for( var name in data )
2824//      {
2825//          named.filter( '[name="'+name+'"]' ).val( data[name] );
2826//      }
2827//     },
2828//
2829// 
2830//     
2831//     put: function( concept, filter, data, oneSide ){
2832//       
2833//       ///////////////////////////// normalize ////////////////////////////////
2834//      if( arguments.length == 2 )
2835//      {
2836//          data = filter;
2837//          filter = false;
2838//      }
2839//      if( typeof data === "undefined" ||
2840//          $.type(data) === "boolean" )
2841//      {
2842//          oneSide = data;
2843//          data = filter;
2844//          filter = false;
2845//      }
2846//     
2847//      if( !concept || !data )
2848//          return( false );
2849//
2850//      var decoder = "", id = false, bothSides = (typeof oneSide === "undefined"), notArray, res;
2851//     
2852//      if( $.type(filter) === "string" )
2853//      {
2854//          id = filter;
2855//          filter = false;
2856//      }
2857//
2858//      if( id )
2859//          data.id = id;
2860//
2861//      if( notArray = ( $.type( data ) !== "array" ) )
2862//          data = [ data ];
2863//
2864//      if( res = internalUrl.exec( concept ) )
2865//      {
2866//          //TODO: verificar se a decodificaçao deve ser feita em cada item do array
2867//          data = this.decode( concept, data );
2868//          concept = res[1];
2869//          decoder = res[2];
2870//      }
2871//
2872//       ////////////////////////////////////////////////////////////////////////
2873//
2874//      if( bothSides || !oneSide )
2875//      {
2876//          var result = false, links = this.links( concept ),
2877//          current = this.check( concept ) || {}, ids = [];
2878//
2879//          for( var i = 0; i < data.length; i++ )
2880//          {
2881//              var key = ids[ ids.length ] = data[i].id || this.generateId( concept ), updateSet = {};
2882//
2883//              ////////////////////////////// linkage /////////////////////////////////   
2884//              for( var link in links )
2885//              {
2886//                  if( data[i][link] )
2887//                  {
2888//                      var isConcept = false;
2889//                   
2890//                      if( isConcept = this.isConcept( concept, link ) )
2891//                          data[i][link] = [ data[i][link] ];
2892//
2893//                      var _this = this;
2894//
2895//                      $.each( data[i][link], function( ii, el ){
2896//
2897//                              var isRef = false;
2898//
2899//                              if( isRef = ($.type(el) === "string") )
2900//                                  el = { id: el };
2901//
2902//                              var nestedLinks = _this.links( links[link], true );
2903//                              //removido pois o mesmo esta gerando inconsistencia em tudo
2904//                              //if( DataLayer.isConcept( links[link], nestedLinks[concept] ) )
2905//                              if( isConcept )
2906//                              {
2907//                                  el[ nestedLinks[link] ] = el[ nestedLinks[link] ] || [];
2908//                                  el[ nestedLinks[link] ].push( key );
2909//                              }
2910//                              else
2911//                                  el[ nestedLinks[link] ] = key;
2912//
2913//                              if( isRef && ( !current[ key ] || !current[ key ][ link ] ||
2914//                                             (isConcept ? current[ key ][ link ] !== el.id : !$.inArray( el.id, current[ key ][ link ] )) ) )
2915//                              {
2916//                                  updateSet[ links[link] ] = updateSet[ links[link] ] || [];
2917//                                  updateSet[ links[link] ].push( el );
2918//                              }
2919//                              else if( !isRef )
2920//                                  data[i][link][ii] = _this.put( links[link], el, oneSide );
2921//                          });
2922//
2923//                      if( isConcept )
2924//                          data[i][link] = data[i][link][0];
2925//                  }
2926//              }
2927//              //////////////////////////////////////////////////////////////////////////
2928//
2929//              if( data[i].id )
2930//                  data[i] = this.merge( current[ data[i].id ], data[i] );
2931//
2932//               current[ key ] = data[i];
2933//
2934//              if( bothSides )
2935//                this.report( concept, key, data[i] );
2936//          }
2937//
2938//          this.store( concept, current );
2939//
2940//          for( var setKey in updateSet )
2941//          {
2942//              if( bothSides )
2943//                  for( var i = 0; i < updateSet[ setKey ].length; i++ )
2944//                    this.report( setKey, updateSet[ setKey ][i].id, updateSet[ setKey ][i] );
2945//                 
2946//              DataLayer.put( setKey, updateSet[ setKey ], false );
2947//          }
2948//      }
2949//
2950//      if( oneSide )
2951//          this.commit( concept, ids/*, true */);
2952//
2953//      this.broadcast( concept, oneSide ? 'server' : bothSides ? 'serverclient' : 'client', true );
2954//
2955//      return( notArray ? ids[0] : ids );
2956//
2957//     },
2958//     
2959//     remove: function( concept, id, oneSide ){
2960//       
2961//      var bothSides = (typeof oneSide === "undefined"),
2962//
2963//      links = this.links( concept ), ids = [],
2964//
2965//      current = this.check( concept, id );
2966//
2967//      if( !current ) return;
2968//     
2969//      if( id )
2970//          current.id = id;
2971//
2972//      if( notArray = ( $.type( current ) !== "array" ) )
2973//          current = [ current ];
2974//
2975//      for( var i = 0; i < current.length; i++ )
2976//      {
2977//          var currentId = ids[ ids.length ] = current[i].id;
2978//
2979//          if( bothSides )
2980//            this.report( concept, currentId, false );
2981//
2982//          if( bothSides || !oneSide )
2983//            this.del( concept, currentId );
2984//
2985//          for( var link in links )
2986//          {
2987//              if( !current[i][link] )
2988//                  continue;
2989//
2990//              var nestedLinks = this.links( links[link], true );
2991//
2992//              if( isConcept = this.isConcept( concept, link ) )
2993//                  current[i][link] = [ current[i][link] ];
2994//
2995//              $.each( current[i][link], function( ii, el ){
2996//
2997//                      el = DataLayer.storage.cache[links[link]][el];
2998//
2999//                      if( notArrayNested = ( $.type( el[ nestedLinks[link] ] ) !== "array" ) )
3000//                          el[ nestedLinks[link] ] = [ el[nestedLinks[link]] ];
3001//
3002//                      el[ nestedLinks[link] ] = $.grep( el[ nestedLinks[link] ], function( nested, iii ){
3003//                          return ( currentId !== nested );
3004//                      });
3005//
3006//                      if( notArrayNested )
3007//                          el[ nestedLinks[link] ] = el[ nestedLinks[link] ][0] || false;
3008//                      if(!el[ nestedLinks[link] ] || !el[ nestedLinks[link] ].length)
3009//                              delete el[ nestedLinks[link] ];
3010//              });
3011//          }
3012//      }
3013//
3014//      if( oneSide )
3015//          this.commit( concept, ids );
3016//
3017//      this.broadcast( concept, oneSide ? 'server' : bothSides ? 'serverclient' : 'client', false );
3018//     },
3019//     
3020//     report: function( concept, id, data )
3021//     {     
3022//      var current = this.check( ':current', concept ) || {};
3023//
3024//      if( !current[ id ] )
3025//          current[ id ] = this.check( concept, id ) || {};
3026//     
3027//      this.store( ':current', concept, current );
3028//
3029//      var diff = this.diff( current[ id ], data );
3030//
3031//      var diffs = this.check( ':diff', concept ) || {};
3032//
3033//      if( diffs[ id ] )
3034//          diff = this.merge( diffs[ id ], diff );
3035//
3036//      if( !diff || !$.isEmptyObject( diff ) )
3037//          diffs[ id ] = diff;
3038//
3039//      this.store( ':diff', concept, diffs );
3040//     },
3041//
3042// //     enqueue: function( queueName, concept, id, data ){
3043// //
3044// //   var queue = this.check( ':' + queueName, concept ) || {};
3045// //
3046// //
3047// //     },
3048// //     
3049// //     dequeue: function( queueName, concept, id ){
3050// //
3051// //   
3052// //
3053// //     },
3054//     
3055//     
3056//     
3057//     rollback: function( concept, ids ){
3058//       
3059//      var queue = this.prepareQ( 'current', concept, ids );
3060//
3061//      ids = [];
3062//
3063//      for( var id in queue )
3064//      {
3065//           this.put( concept, id, queue[id], false );
3066//
3067//           ids[ ids.length ] = id;
3068//      }
3069//
3070//      this.clearQ( concept, ( ids.length ? ids : false ) );
3071//
3072//      this.broadcast( concept, 'revert' );
3073//       
3074//     },
3075//     
3076//     prepareQ: function( queueName, concept, ids ){
3077//       
3078//       var notArray = false;
3079//       
3080//       if( notArray = ($.type(concept) !== "array") )
3081//        concept = [ concept ];
3082//       
3083//       var q = {};
3084//       
3085//       for( var i = 0; i < concept.length; i++ )
3086//       {
3087//        var queue = this.check( ':' + queueName, concept[i] || false );
3088//       
3089//        if( !queue ) continue;
3090//
3091//        if( ids )
3092//        {
3093//            if( $.type(ids) !== "array" )
3094//                ids = [ ids ];
3095//
3096//            var filtered = {};
3097//
3098//            for( var ii = 0; ii < ids.length; ii++ )
3099//            {
3100//                filtered[ ids[ii] ] = queue[ ids[ii] ];
3101//            }
3102//
3103//            queue = filtered;
3104//        }
3105//
3106//        q[ concept[i] ] = queue;
3107//       }
3108//       
3109//       return( notArray ? q[ concept[0] ] : q );
3110//     },
3111//     
3112//     clearQ: function( concept, ids ){
3113//       
3114//              var current = this.check( ':current', concept || false );
3115//      var diffs = this.check( ':diff', concept || false );
3116//
3117//      if( !ids )
3118//          current = diffs = {};
3119//      else
3120//      {
3121//          if( notArray = ($.type(ids) !== "array") )
3122//            ids = [ ids ];
3123//
3124//          for( var i = 0; i < ids.length; i++ )
3125//          {
3126//              delete current[ ids[i] ];
3127//              delete diffs[ ids[i] ];
3128//          }
3129//      }
3130//
3131//      this.store( ':current', concept, current );
3132//      this.store( ':diff', concept, diffs );
3133//     },
3134//
3135//     commit: function( concept, ids, callback ){
3136//       
3137//      var queue = this.prepareQ( 'diff', concept, ids );
3138//
3139//      this.sync( queue, !$.isArray(concept) && concept || false, callback );
3140//     },
3141//     
3142//     sync: function( queue, concept, callback ){
3143//
3144//      if( !queue || $.isEmptyObject( queue ) )
3145//          return;
3146//
3147//      if( concept )
3148//      {
3149//        var helper = {};
3150//        helper[concept] = queue;
3151//        queue = helper;
3152//      }
3153//
3154//      var data = {}, URIs = {};
3155//
3156//      for( var concept in queue )
3157//          for( var id in queue[concept] )
3158//          {
3159//              data[ this.URI( concept, id ) ] = queue[concept][id];
3160//              URIs[ this.URI( concept, id ) ] = { concept: concept, id: id };
3161//          }
3162//
3163//      if( $.isEmptyObject( data ) )
3164//          return;
3165//
3166//      this.dispatch( "Sync", data, function( data, status, jqXHR ){
3167//
3168// //       switch( status )
3169// //       {
3170// //         case "error":
3171// //         case "parsererror":
3172// //           return DataLayer.rollback( concept, URI );
3173// //         case "success":
3174// //           return DataLayer.commit();
3175// //         case "timeout":
3176// //         case "notmodified":
3177// //       }
3178//
3179//          var received = DataLayer.receive( data );
3180//
3181//          for( var URI in URIs )
3182//              if( typeof received[URI] !== "undefined" )
3183//                  DataLayer.clearQ( URIs[URI].concept, URIs[URI].id );
3184//
3185//          if( callback )
3186//              callback( received );
3187//
3188// //       for( var URI in data )
3189// //       {
3190// //           var parsed = DataLayer.parseURI( URI ),
3191// //   
3192// //           concept = parsed[1], id = parsed[3];
3193// //
3194// //           if( $.type(data[URI]) === "string" )
3195// //           {
3196// //             //TODO:threat the exception thrown
3197// //             DataLayer.rollback( concept, id );
3198// //             delete URIs[ URI ];
3199// //             continue;
3200// //           }
3201// //
3202// //           if( data[URI] === false ){
3203// //             DataLayer.remove( concept, id, false );
3204// //             continue;
3205// //           }
3206// //
3207// //           if( id !== data[URI].id )
3208// //             DataLayer.move( concept, id, data[URI].id );
3209// //           
3210// //           DataLayer.put( concept, id, data[URI], false );
3211// //       }
3212// //       
3213// //       for( var URI in URIs )
3214// //            DataLayer.clearQ( URIs[URI].concept, URIs[URI].id );
3215// //       
3216// //       if( callback )
3217// //           callback();
3218//
3219//      }, true );
3220//
3221//     },
3222//     
3223//     receive: function( data ){
3224//       
3225//      var received = {};
3226//     
3227//          for( var URI in data )
3228//          {
3229//              var parsed = DataLayer.parseURI( URI ),
3230//   
3231//          concept = parsed[4], id = parsed[5];
3232//
3233//          received[ URI ] = data[ URI ];
3234//
3235//              if( $.type(data[URI]) === "string" )
3236//              {
3237//                //TODO:threat the exception thrown
3238//                DataLayer.rollback( concept, id );
3239//                continue;
3240//              }
3241//
3242//              if( data[URI] === false ){
3243//                DataLayer.remove( concept, id, false );
3244//                continue;
3245//              }
3246//
3247//              if( id !== data[URI].id )
3248//                DataLayer.move( concept, id, data[URI].id );
3249//             
3250//              DataLayer.put( concept, id, data[URI], false );
3251//          }
3252//         
3253//      return( received );
3254//         
3255//     },
3256//     
3257//     unique: function( origArr ){
3258//
3259//      var newArr = [];
3260//       
3261//      for ( var x = 0; x < origArr.length; x++ )
3262//      {
3263//              var found = false;
3264//          for ( var y = 0; !found && y < newArr.length; y++ )
3265//              if ( origArr[x] === newArr[y] ) 
3266//                found = true;
3267//
3268//          if ( !found )
3269//              newArr[ newArr.length ] = origArr[x];
3270//      }
3271//
3272//      return newArr;
3273//     },
3274//
3275//     merge: function( current, data ){
3276//       
3277//      return this.copy(  data, current );
3278//
3279// //   return $.extend( current, data );
3280//
3281//     },
3282//     
3283//     // clone objects, skip other types.
3284//     clone: function(target) {
3285//          if ( typeof target == 'object' ) {
3286//                  Clone.prototype = target;
3287//                  return new Clone();
3288//          } else {
3289//                  return target;
3290//          }
3291//     },
3292//       
3293//     // Shallow Copy
3294//     shallowCopy: function(target) {
3295//          if (typeof target !== 'object' ) {
3296//                  return target;  // non-object have value sematics, so target is already a copy.
3297//          } else {
3298//                  var value = target.valueOf();
3299//                  if (target != value) {
3300//                          // the object is a standard object wrapper for a native type, say String.
3301//                          // we can make a copy by instantiating a new object around the value.
3302//                          return new target.constructor(value);
3303//                  } else {
3304//                          // ok, we have a normal object. If possible, we'll clone the original's prototype
3305//                          // (not the original) to get an empty object with the same prototype chain as
3306//                          // the original.  If just copy the instance properties.  Otherwise, we have to
3307//                          // copy the whole thing, property-by-property.
3308//                          if ( target instanceof target.constructor && target.constructor !== Object ) {
3309//                                  var c = clone(target.constructor.prototype);
3310//       
3311//                                  // give the copy all the instance properties of target.  It has the same
3312//                                  // prototype as target, so inherited properties are already there.
3313//                                  for ( var property in target) {
3314//                                          if (target.hasOwnProperty(property)) {
3315//                                                  c[property] = target[property];
3316//                                          }
3317//                                  }
3318//                          } else {
3319//                                  var c = {};
3320//                                  for ( var property in target ) c[property] = target[property];
3321//                          }
3322//                         
3323//                          return c;
3324//                  }
3325//          }
3326//     },
3327//
3328//     // entry point for deep copy.
3329//     // source is the object to be deep copied.
3330//     // depth is an optional recursion limit. Defaults to 256.
3331//     // deep copy handles the simple cases itself: non-objects and object's we've seen before.
3332//     // For complex cases, it first identifies an appropriate DeepCopier, then delegate the details of copying the object to him.
3333//     copy: function(source, result, depth) {
3334//       
3335//          // null is a special case: it's the only value of type 'object' without properties.
3336//          if ( source === null ) return null;
3337//
3338//          // All non-objects use value semantics and don't need explict copying.
3339//          if ( typeof source !== 'object' ) return source;
3340//
3341//          if( !depth || !(depth instanceof RecursionHelper) ) depth = new RecursionHelper(depth);
3342//
3343//          var cachedResult = depth.getCachedResult(source);
3344//
3345//          // we've already seen this object during this deep copy operation
3346//          // so can immediately return the result.  This preserves the cyclic
3347//          // reference structure and protects us from infinite recursion.
3348//          if ( cachedResult ) return cachedResult;
3349//
3350//          // objects may need special handling depending on their class.  There is
3351//          // a class of handlers call "DeepCopiers"  that know how to copy certain
3352//          // objects.  There is also a final, generic deep copier that can handle any object.
3353//          for ( var i=0; i<this.comparators.length; i++ ) {
3354//
3355//                  var comparator = this.comparators[i];
3356//
3357//                  if ( comparator.can(source) ) {
3358//     
3359//                          // once we've identified which DeepCopier to use, we need to call it in a very
3360//                          // particular order: create, cache, populate.  This is the key to detecting cycles.
3361//                          // We also keep track of recursion depth when calling the potentially recursive
3362//                          // populate(): this is a fail-fast to prevent an infinite loop from consuming all
3363//                          // available memory and crashing or slowing down the browser.
3364//       
3365//                          if( !result )
3366//                              // Start by creating a stub object that represents the copy.
3367//                              result = comparator.create(source);
3368//                          else if( !comparator.can(result) )
3369//                              throw new Error("can't compare diferent kind of objects.");
3370//
3371//                          // we now know the deep copy of source should always be result, so if we encounter
3372//                          // source again during this deep copy we can immediately use result instead of
3373//                          // descending into it recursively. 
3374//                          depth.cacheResult(source, result);
3375//
3376//                          // only DeepCopier.populate() can recursively deep copy.  So, to keep track
3377//                          // of recursion depth, we increment this shared counter before calling it,
3378//                          // and decrement it afterwards.
3379//                          depth.depth++;
3380//                          if ( depth.depth > depth.maxDepth ) {
3381//                                  throw new Error("Exceeded max recursion depth in deep copy.");
3382//                          }
3383//
3384//                          // It's now safe to let the comparator recursively deep copy its properties.
3385//                          var returned = comparator.populate( function(source, result) { return DataLayer.copy(source, result, depth); }, source, result );
3386//     
3387//                              if(returned)
3388//                                      result = returned;
3389//
3390//                          depth.depth--;
3391//
3392//                          return result;
3393//                  }
3394//          }
3395//          // the generic copier can handle anything, so we should never reach this line.
3396//          throw new Error("no DeepCopier is able to copy " + source);
3397//     },
3398//
3399//     // publicly expose the list of deepCopiers.
3400//     comparators: [],
3401//
3402//     // make deep copy() extensible by allowing others to
3403//     // register their own custom Comparators.
3404//     registerComparator: function(comparatorOptions) {
3405//
3406//        // publicly expose the Comparator class.
3407//        var comparator = {
3408//
3409//            // determines if this Comparator can handle the given object.
3410//            can: function(source) { return false; },
3411//     
3412//            // starts the deep copying process by creating the copy object.  You
3413//            // can initialize any properties you want, but you can't call recursively
3414//            // into the copy().
3415//            create: function(source) { },
3416//
3417//            // Completes the deep copy of the source object by populating any properties
3418//            // that need to be recursively deep copied.  You can do this by using the
3419//            // provided deepCopyAlgorithm instance's copy() method.  This will handle
3420//            // cyclic references for objects already deepCopied, including the source object
3421//            // itself.  The "result" passed in is the object returned from create().
3422//            populate: function(deepCopyAlgorithm, source, result) {}
3423//        };
3424//
3425//        for ( var key in comparatorOptions ) comparator[key] = comparatorOptions[key];
3426//
3427//        this.comparators.unshift( comparator );
3428//     },
3429// 
3430//     diff: function( base, toDiff ){
3431//
3432//      if( typeof base === 'undefined' || $.isEmptyObject(base) )
3433//          return( toDiff );
3434//
3435//      if( toDiff === false )
3436//          return( false );
3437//
3438//      toDiff = $.extend( {}, toDiff );
3439//
3440//      for( var key in toDiff )
3441//      {
3442//          switch( $.type(toDiff[key]) )
3443//          {
3444//            case 'object':
3445//              if( $.isEmptyObject(toDiff[key] = this.diff( base[key], toDiff[key] )) )
3446//                delete toDiff[key];
3447//            break;
3448//            case 'array':
3449//              if( base[key] && !(toDiff[key] = $.grep( toDiff[key], function( el, i ){ return( $.inArray( el, base[key] ) === -1 ); } )).length )
3450//                delete toDiff[key];
3451//            break;
3452//            default:
3453//              if( base[key] == toDiff[key] )
3454//                delete toDiff[key];
3455//          }
3456//      }
3457//
3458//      return( toDiff );
3459//
3460//     },
3461//     
3462//     links: function( concept, reverse ){
3463//
3464//      if( !this.links[ concept ] )
3465//      {
3466//          var result = this.dispatch( "links", { concept: concept } ) || false;
3467//
3468//          if( !result )
3469//              return( false );
3470//
3471//          this.concepts[ concept ] = $.extend( this.concepts[ concept ] || {},
3472//                                               result['concepts'] || {} );
3473//
3474//          this.links[ concept ] =  result['links'] || {};
3475//          this.nestedLinks[ concept ] = result['nestedLinks'] || {};
3476//      }
3477//
3478//      if( reverse )
3479//      {
3480//          return( this.nestedLinks[ concept ] );
3481// //       var reverted = {}, llinks = this.links[ concept ];
3482// //     
3483// //       for( var key in llinks )
3484// //           reverted[ llinks[key] ] = key;
3485// //
3486// //       return( reverted );
3487//      }
3488//
3489//      return( this.links[ concept ] );
3490//
3491//     },
3492//     
3493//     isConcept: function( concept, attr ){
3494//       
3495//      if( typeof this.concepts[concept] === "undefined" )
3496//      {
3497//          this.links( concept );
3498//      }
3499//
3500//      return !!this.concepts[ concept ][ attr ];
3501//     },
3502//     
3503//     URI: function( concept, URI, context ){
3504//       
3505//      if( res = internalUrl.exec( concept ) )
3506//          concept = res[1];
3507//     
3508//      context = context ? "(" + context + ")" : "";
3509//       
3510//      if( URI )
3511//          return( concept + context + "://" + URI );
3512//      else
3513//          return( concept );
3514//       
3515//     },
3516//     
3517//     parseURI: function( URI ){
3518//
3519//      return internalUri.exec( URI ) || false;
3520//
3521//     },
3522//     
3523//     
3524//   
3525//     
3526//     generateId: function( concept ){
3527//       
3528//      var newId = this.counter + "(javascript)";
3529//       
3530//      this.store( ":counter", (this.counter++) + "" );
3531//     
3532//      return( newId );
3533//     },
3534//   
3535//
3536//   
3537//
3538//     get: function( concept, /*URI, */filter, oneSide ){
3539//
3540//      ///////////////////////////// normalize ////////////////////////////////
3541//      if( arguments.length == 2 && $.type(filter) === "boolean" )
3542//      {
3543//          oneSide = filter;
3544//          filter = false;
3545//      }
3546//     
3547//      var encoder = false, id = false, bothSides = (typeof oneSide === 'undefined'), res;
3548//     
3549//      if( $.type(filter) === "string" )
3550//      {
3551//          id = filter;
3552//          filter = false;
3553//      }
3554//
3555//      filter = filter || false;
3556//
3557//      if( !concept )
3558//          return( false );
3559//
3560//      if( res = internalUrl.exec( concept ) )
3561//      {
3562//          encoder = concept;
3563//          concept = res[1];
3564//
3565//          if( filter )
3566//              filter = this.criteria( encoder, filter );
3567//      }
3568//     
3569//      if ( $.type(filter) === "array" )
3570//      {
3571//          filter = { filter: filter, criteria: false };
3572//      }
3573//     
3574//      //////////////////////////////////////////////////////////////////////////
3575//     
3576//      var result = false;
3577//
3578//      if( bothSides || !oneSide )
3579//          result = this.check( concept, id || filter );
3580//
3581//      if( !result && (bothSides || oneSide) )
3582//      {
3583//          result = this.request( concept, id || filter.filter, filter.criteria );
3584//
3585//          if( result && bothSides && (!filter ||
3586//                                      !filter.criteria ||
3587//                                      !filter.criteria.format) )
3588//          {
3589//            var newResult = [];
3590//         
3591//            for( var i = 0; i < result.length; i++ )
3592//                newResult[i] = $.extend( {}, result[i] );
3593//
3594//            this.put( concept, id, newResult, false );
3595//          }
3596//      }
3597//
3598//      if( /*result &&*/ encoder )
3599//          result = this.encode( encoder, result, filter ); //TODO: retirar o filtro no método encode
3600//
3601//      return( result );
3602//     },
3603//     
3604//     filter: function( base, filter, criteria ){
3605//       
3606//      var filtered = [];
3607//       
3608//      for( var key in base )
3609//      {
3610// //       if( !noGroup )
3611// //           for( var i = 0, current = original; i < filter.length && ( current === original ); i++ )
3612// //               current = this.compare( operator, current, this.compare( base[key], filter[i] ) );
3613//
3614//          if( this.storage.filter( base[key], filter ) )
3615//              filtered[ filtered.length ] = key;
3616//      }
3617//
3618//      return( filtered );
3619//     },
3620//     
3621//     compare: function( operator, base, test ){
3622//       
3623//       switch( operator )
3624//       {
3625//        case '*':  return RegExp( ".*" + test + ".*" ).test( base );
3626//        case '^':  return RegExp( "^" + test +  ".*" ).test( base );
3627//        case '$':  return RegExp( ".*"  + test + "$" ).test( base );
3628//
3629//        case '&':  return ( base && test );
3630//        case '|':  return ( base || test );
3631//
3632//        case '=':  return ( base == test );
3633//        case '<=': return ( base <= test );
3634//        case '>=': return ( base >= test );
3635//        case '>':  return ( base <  test );
3636//        case '<':  return ( base >  test );
3637//       }
3638//       
3639//     },
3640//     
3641// //     clone: function( object ){
3642// //
3643// //   new { prototype: object };
3644// //
3645// //     },
3646//
3647//     check: function( namespace, keys ){
3648//
3649//      if( !namespace )
3650//          return( false );
3651//
3652//      var result = this.storage.get( namespace );
3653//
3654//      if( !keys || !result )
3655//        return( result || false );
3656//
3657//      if( notArray = $.type(keys) === "string" )
3658//          keys = [ keys ];
3659//      else if( $.type(keys) !== "array" )
3660//          keys = this.filter( result, keys.filter, keys.criteria );
3661//
3662//      var res = [];
3663//
3664//      for( var i = 0; i < keys.length; i++ )
3665//          res[ res.length ] = result[keys[i]];
3666//
3667//      return( notArray ? res[0] || false : res.length ? res : false );
3668//     },
3669//
3670//     storage: {
3671//       
3672//      cache: {},
3673//       
3674//      set: function( key, value ){
3675//
3676//          this.cache[key] = value;
3677//
3678//      },
3679//      get: function( key ){
3680//
3681//          return DataLayer.copy( this.cache[key] );
3682//
3683//      },
3684//      del: function( key ){
3685//
3686//          delete this.cache[key];
3687//
3688//      },
3689//     
3690//      filter: function( base, filter ){
3691//       
3692//          var bool, op = filter.shift();
3693//
3694//          switch( op )
3695//          {
3696//              case 'IN':
3697//                for( var i = 0, f = []; i < filter[1].length || !(filter = f); i++ )
3698//                    f[i] = [ '=', filter[0], filter[1][i] ];
3699//              case 'OR':
3700//                  op = '|';
3701//                  bool = false;
3702//              break;
3703//              case 'AND':
3704//                  op = '&';
3705//                  bool = true;
3706//              break;
3707//              default : return DataLayer.compare( op, base[ filter[0] ], filter[1] );
3708//          }
3709//         
3710//          for( var strict = bool;
3711//
3712//              filter.length && ( strict ? bool : !bool );
3713//         
3714//              bool = DataLayer.compare( op, bool, this.filter( base, filter.shift() ) ) );
3715//
3716//          return( bool );
3717//      }
3718//     },
3719//
3720//     flush: function(){
3721//
3722//     },
3723//     
3724//     restore: function(){
3725//       
3726//     },
3727//
3728//     store: function( namespace, key, data ){
3729//
3730//      if( !data )
3731//        return this.storage.set( namespace, key );
3732//
3733//      var res = this.check( namespace ) || {};
3734//
3735//      res[key] = data;
3736//
3737//      return this.storage.set( namespace, res );
3738//     },
3739//
3740//     del: function( namespace, key ){
3741//       
3742//      if( !key )
3743//        return this.storage.del( namespace );
3744//
3745//      var res = this.check( namespace ) || {};
3746//
3747//      delete res[key];
3748//
3749//      return this.storage.set( namespace, res );
3750//       
3751//     },
3752//     
3753//      move: function( concept, oldId, newId ){
3754//
3755//      this.put( concept, newId, this.check( concept, oldId ), false );
3756//
3757//      this.remove( concept, oldId, false );
3758//     },
3759//     
3760//
3761//     
3762//     
3763//     
3764//     request: function( concept, filter, criteria ){
3765//
3766//       var id = false, criteria = criteria || {};
3767//
3768//       if( $.type(filter) === "string" )
3769//       {
3770//        id = filter;
3771//        filter = false;
3772//       }
3773//
3774//       return this.dispatch( "request", {
3775//
3776//        concept: concept || '',
3777//        id: id || '',
3778//        filter: filter || '',
3779//        criteria: criteria || '',
3780//        service: criteria.service || '',
3781//        properties: criteria.properties || ''
3782//
3783//       } );
3784//     },
3785//
3786//     
3787//     //         sync: function( data, callback ){
3788// //
3789// //   if( !data || $.isEmptyObject( data ) )
3790// //       return;
3791// //       
3792// //   this.send( "Sync", data, function( data, status, jqXHR ){
3793// //
3794// // //            switch( status )
3795// // //            {
3796// // //              case "error":
3797// // //              case "parsererror":
3798// // //                return DataLayer.rollback( concept, URI );
3799// // //              case "success":
3800// // //                return DataLayer.commit();
3801// // //              case "timeout":
3802// // //              case "notmodified":
3803// // //            }
3804// //
3805// //       if( callback )
3806// //       {
3807// //           var result = callback( data, status, jqXHR );
3808// //
3809// //           if( result === false )
3810// //               return;
3811// //           else if( typeof result != "undefined" )
3812// //               data = result;
3813// //       }
3814// //
3815// //       for( var URI in data )
3816// //       {
3817// //           var parsed = DataLayer.parseURI( URI ),
3818// //   
3819// //           concept = parsed[1], /*URI = parsed[3],*/
3820// //
3821// //           links = DataLayer.links( concept );
3822// //
3823// //           for( var linkName in links )
3824// //           {
3825// //               var subURI = data[URI][linkName];
3826// //
3827// //               if( subURI && data[subURI] )
3828// //               {
3829// //                   data[URI][linkName] = DataLayer.put( linkName, subURI, data[subURI], false );
3830// //
3831// //                   delete( data[subURI] );
3832// //               }
3833// //           }
3834// //
3835// //           DataLayer.put( concept, URI, data[URI], false );
3836// //       }
3837// //   }, true );
3838// //
3839// //     },
3840//
3841// //     report: function( concept, URI, data, sync )
3842// //     {
3843// //   var current = this.dequeue( 'current', concept, URI );
3844// //
3845// //   if( !current )
3846// //       this.enqueue( 'current', concept, URI, ( current = this.check( concept, URI ) || {} ) );
3847// //
3848// //   var diff = this.diff( current, data );
3849// //
3850// //   if( !diff )
3851// //       this.dequeue( 'current', concept, URI, true );
3852// //   else
3853// //       this.enqueue( 'diff', concept, URI, diff );
3854// //   
3855// //   if( sync )
3856// //       this.commit( concept, URI, function(){
3857// //
3858// //           DataLayer.set( concept, URI, data, false );
3859// //
3860// //       });
3861// //     },
3862//     
3863// //     enqueue: function( type, concept, URI, obj ){
3864// //       
3865// //   //var newURI = this.URI( concept, URI );
3866// //   
3867// //   if( !this.queue[type] )
3868// //       this.queue[type] = {};
3869// //
3870// //   if( !this.queue['all'] )
3871// //       this.queue['all'] = {};
3872// //   
3873// //   if( !this.queue[type][concept] )
3874// //       this.queue[type][concept] = {};
3875// //   
3876// //   if( !this.queue['all'][type] )
3877// //       this.queue['all'][type] = {};
3878// //   
3879// //   if( !this.queue['all'][type][/*new*/URI] )
3880// //       this.queue[type][concept][URI] = this.queue['all'][type][/*new*/URI] = obj;
3881// //
3882// //   this.store( ':queue', this.queue );
3883// //     },
3884// //     
3885// //     dequeue: function( type, concept, URI, remove ){
3886// //       
3887// //       ///////////////////////////// normalize ////////////////////////////////
3888// //   if( arguments.length < 4 && $.type(URI) === 'boolean' )
3889// //   {
3890// //       remove = URI;
3891// //       URI = false;
3892// //   }
3893// //   if( arguments.length < 3 && $.type(concept) === 'boolean' )
3894// //   {
3895// //       remove = concept;
3896// //       concept = false;
3897// //   }
3898// //       //////////////////////////////////////////////////////////////////////////
3899// //       
3900// //   if( !this.queue[type] || !this.queue['all'] )
3901// //       return( false );
3902// //   
3903// //   if( !concept )
3904// //   {
3905// //       var obj = this.queue['all'][type];
3906// //       
3907// //       if( remove )
3908// //       {
3909// //           delete this.queue['all'][type];
3910// //           delete this.queue[type];
3911// //       }
3912// //
3913// //       this.store( ':queue', this.queue );
3914// //       return( obj );
3915// //   }
3916// //
3917// //   if( !this.queue[type][concept] )
3918// //       return( false );
3919// //   
3920// //   if( !URI )
3921// //   {
3922// //       var obj = this.queue[type][concept];
3923// //
3924// //       if( remove )
3925// //       {
3926// //           var URIs = this.queue[type][concept];
3927// //
3928// //           for( var subURI in URIs )
3929// //                delete this.queue['all'][type][subURI];
3930// //
3931// //           delete this.queue[type][concept];
3932// //       }
3933// //
3934// //       this.store( ':queue', this.queue );
3935// //       return( obj );
3936// //   }
3937// //
3938// // //        var newURI = URI ? this.URI( concept, URI ) : concept;
3939// //   
3940// //   var obj = this.queue['all'][type][/*new*/URI];
3941// //   
3942// //   if( remove )
3943// //   {
3944// //       delete this.queue['all'][type][/*new*/URI];
3945// //       delete this.queue[type][concept][URI];
3946// //   }
3947// //
3948// //   this.store( ':queue', this.queue );
3949// //   return( obj );
3950// //     },
3951//     
3952//            //TODO: definir a 'usage' desta função e refatora-la
3953// //     set: function( concept, filter, data, oneSide ){
3954// //
3955// //   ///////////////////////////// normalize ////////////////////////////////
3956// //   if( arguments.length == 2 )
3957// //   {
3958// //       data = filter;
3959// //       filter = false;
3960// //   }
3961// //   if( $.type(data) === "boolean" )
3962// //   {
3963// //       oneSide = data;
3964// //       data = filter;
3965// //       filter = false;
3966// //   }
3967// //   
3968// //   if( !concept || !data )
3969// //       return( false );
3970// //
3971// //   var decoder = "", URI = false, bothSides = (typeof oneSide === "undefined");
3972// //   
3973// //   if( $.type(filter) === "string" )
3974// //   {
3975// //       URI = filter;
3976// //       filter = false;
3977// //   }
3978// //
3979// //   if( res = internalUrl.exec( concept ) )
3980// //   {
3981// //       //TODO: verificar se a decodificaçao deve ser feita em cada item do array
3982// //       data = this.decode( concept, data );
3983// //       concept = res[1];
3984// //       decoder = res[2];
3985// //   }
3986// //   ///////////////////////////////////////////////////////////////////////////
3987// //
3988// //   if( bothSides || oneSide )
3989// //       this.report( concept, URI, data, !bothSides );
3990// //
3991// //   if( bothSides || !oneSide )
3992// //   {
3993// //       if( URI )
3994// //       {
3995// //         var helper = {};
3996// //         helper[URI] = data;
3997// //         data = helper;
3998// //       }
3999// //
4000// //       for( var URI in data )
4001// //       {
4002// //           var current = this.check( concept, URI ) || {};
4003// //
4004// //           data[URI] = this.merge( current, data[URI] );
4005// //
4006// //           this.store( concept, URI, data[URI] );
4007// //       }
4008// //
4009// //   }
4010// //
4011// //   this.broadcast( concept, oneSide ? 'client' : 'server' );
4012// //
4013// //   return( true );
4014// //     },
4015// //     put: function( concept, URI, data, oneSide ){
4016// //       
4017// //       ///////////////////////////// normalize ////////////////////////////////
4018// //   if( $.type(URI) !== "string" && arguments.length < 4 )
4019// //   {
4020// //       oneSide = data;
4021// //       data = URI;
4022// //       URI = false;
4023// //   }
4024// //       ////////////////////////////////////////////////////////////////////////
4025// //       
4026// //       ////////////////////////////// linkage /////////////////////////////////
4027// //   var result = false, links = this.links( concept );
4028// //
4029// //   for( var link in links )
4030// //   {
4031// //       if( data[link] )
4032// //       {
4033// //           if( $.isArray( data[link] ) )
4034// //           {
4035// //               data[link] = this.put( links[link], data[link].URI, data[link], oneSide );
4036// //           }
4037// //           else if( $.isObject( data[link] ) )
4038// //           {
4039// //               $.each( data[link], function( i, el ){
4040// //
4041// //                     data[link][i] = this.put( links[link], el.URI, el, oneSide );
4042// //
4043// //               });
4044// //           }
4045// //       }
4046// //   }
4047// //       //////////////////////////////////////////////////////////////////////////
4048// //     
4049// //   if( typeof data.URI === "undefined" )
4050// //   {
4051// //       URI = this.add( concept, data, oneSide );
4052// //   }
4053// //   else if( data.URI === false )
4054// //   {
4055// //       status = this.remove( concept, URI, oneSide );
4056// //   }
4057// //   else
4058// //   {
4059// //       status = this.set( concept, URI, data, oneSide );
4060// //   }
4061// //
4062// //   if( URI && data.URI && URI !== data.URI )
4063// //       this.move( concept, URI, data.URI );
4064// //
4065// //   return( data.URI || URI );
4066// //
4067// //     },
4068//     
4069//     //     add: function( concept, data, oneSide ){
4070// //       
4071// //       ///////////////////////////// normalize ////////////////////////////////
4072// //   if( !concept || !data )
4073// //       return( false );
4074// //
4075// //   if( res = internalUrl.exec( concept ) )
4076// //   {
4077// //       //TODO: verificar se a decodificaᅵᅵo deve ser feita em cada item do array
4078// //       data = this.decode( concept, data );
4079// //       concept = res[1];
4080// //       decoder = res[2];
4081// //   }
4082// //
4083// //   var bothSides = (typeof oneSide === "undefined"), uris = [];
4084// //
4085// //   if( notArray = $.type(data) !== "array" )
4086// //       data = [ data ];
4087// //       //////////////////////////////////////////////////////////////////////////
4088// //
4089// //   for( var i = 0; i < data.length; i++ )
4090// //   {
4091// //       var URI = uris[i] = this.generateURI( concept );
4092// //
4093// //       this.set( concept, URI, data[i], oneSide );
4094// //   }
4095// //
4096// //   return( notArray ? uris[0] : uris );
4097// //     },
4098// //      put: function( concept, data ){
4099// //
4100// //   var decoder = "";
4101// //
4102// //   if( res = internalUrl.exec( concept ) )
4103// //   {
4104// //       data = this.decode( concept, data );
4105// //       concept = res[1];
4106// //       decoder = res[2];
4107// //   }
4108// //
4109// //   var New = [], Update = [], uris = [];
4110// //
4111// //   if( notArray = $.type(data) !== "array" )
4112// //       data = [ data ];
4113// //   
4114// //   for( var i = 0; i < data.length; i++ )
4115// //   {
4116// //       if( !data[i].URI )
4117// //       {
4118// //           uris[ uris.length ] = data[i].URI = this.create( concept, data[i] );
4119// //           New[ New.length ] = data[i];
4120// //           continue;
4121// //       }
4122// //
4123// //       for( var key in data[i] )
4124// //           if( klass = this.isReference( concept, key, data[i][key] ) )
4125// //                 data[i][key] = this.put( klass + decoder, data[i][key] );
4126// //
4127// //       Update[ Update.length ] = this.update( concept, data[i].URI, data[i] );
4128// //   }
4129// //
4130// //   this.report( concept, { "created": New, "updated": Update });
4131// //
4132// //   return( notArray ? uris[0] : uris );
4133// //     },
4134// //     merge: function( concept, current, data ){
4135// //
4136// //   current = current || {};
4137// //
4138// //   for( var key in data )
4139// //       current[key] = (klass = this.isReference( concept, key, data[key] )) ?
4140// //                      this.merge( klass, current[key], data[key] ) : data[key];
4141// //
4142// //   return( current );
4143// //     },
4144// //
4145// //     isReference: function( concept, key, value ){
4146// //
4147// //       return( ($.type(value) === "object" ||
4148// //          $.type(value) === "array" )? this.links[concept][key] : false );
4149// //
4150// //     },
4151// //     
4152// //     set: function( concept, data, URI, mergeable ){
4153// //   
4154// //   if( URI )
4155// //   {
4156// //       var res = this.get( concept, true ) || {};
4157// //       
4158// //       if( mergeable )
4159// //           data = this.merge( res[URI] || {}, data );
4160// //
4161// //       res[URI] = data;
4162// //
4163// //       data = res;
4164// //   }
4165// //
4166// //   return this.store( concept, data );
4167// //     },   
4168// //
4169// //     create: function( concept, data ){
4170// //
4171// //       if( notArray = ($.type(data) !== "array") )
4172// //       data = [ data ];
4173// //
4174// //       var uris = [];
4175// //
4176// //       for( var i = 0; i < data.length; i++ )
4177// //       {
4178// //     uris[ uris.length ] = data[i].URI = "javascript://" + (this.counter + i);
4179// //
4180// //     this.set( concept, data[i], data[i].URI );
4181// //       }
4182// // 
4183// //       this.set( ":counter", (this.counter += data.length) );
4184// //
4185// //       return notArray ? uris[0] : uris;
4186// //     },
4187// //
4188// //     update: function( concept, URI, data )
4189// //     {
4190// //   var target = this.check( concept, URI ) || {};
4191// //
4192// //   target = this.merge( concept, target, data );
4193// //
4194// //   if( target.URI !== URI )
4195// //       this.remove( concept, URI );
4196// //
4197// //   this.set( concept, target, target.URI );
4198// //
4199// //   return( target );
4200// //     },
4201// //
4202// //     remove: function( concept, URI ){
4203// //
4204// //   if( !URI )
4205// //       return this.storage.del( concept );
4206// //
4207// //   var res = this.check( concept );
4208// //
4209// //   delete res[URI];
4210// //   
4211// //   this.set( concept, res );
4212// //     },
4213// //
4214// //     del: function( concept, URI ){
4215// //
4216// //   this.remove( concept, URI );
4217// //
4218// //   this.report( concept, { "deleted": { 'URI': URI } });
4219// //     },
4220// //
4221// //     report: function( concept, changes ){
4222// //
4223// //       this.broadcast( concept, changes.created, changes.updated, changes.deleted );
4224// //
4225// //   if( changes.created )
4226// //       this.sync( concept, changes.created, 'create' );
4227// //   if( changes.updated )
4228// //       this.sync( concept, changes.updated, 'update' );
4229// //   if( changes.deleted )
4230// //       this.sync( concept, changes.deleted, 'delete' );
4231// //
4232// //     },
4233// //
4234// //
4235// //    sync: function( concept, data, type ){
4236// //
4237// //   if( $.type(data) !== "array" )
4238// //       data = [ data ];
4239// //
4240// //   $.each( data, function( i, el ){
4241// //
4242// //      DataLayer.send( concept, el, type );
4243// //
4244// //   });
4245// //
4246// //     },
4247// //     
4248// //     
4249// //     
4250// //     
4251// //
4252// //     request: function( concept, URI, filter ){
4253// //
4254// // //       if( startsDoubleDot.test(concept) )
4255// // //          return( false );
4256// //
4257// //       filter = filter || {};
4258// //
4259// //       if( URI )
4260// //   filter.URI = URI;
4261// //
4262// //       return this.send( concept, filter, "read", true );
4263// //
4264// //     },
4265// //
4266// //     send: function( concept, data, type, wait ){
4267// //
4268// //       switch( type )
4269// //       {
4270// //   case "create": type = "POST"; break;
4271// //   case "update": type = "PUT"; break;
4272// //   case "delete": type = "DELETE"; break;
4273// //   case "read": type = "GET"; break;
4274// //       }
4275// //
4276// //       var url = this.basePath + concept;
4277// //
4278// //       var result = [], notArray = false;
4279// //
4280// // //      alert( data.URI );
4281// //
4282// //       if( data.URI && data.URI.indexOf("javascript://") !== 0 )
4283// //     url += "/" + data.URI;
4284// //
4285// //       var callback = function( dt, textStatus, jqXHR ){
4286// //
4287// //       if( notArray = (!$.isArray( dt )) )
4288// //           dt = [ dt ];
4289// //
4290// //       $.each( dt, function( i, el ){
4291// //
4292// //           if( !el || !el.URI )
4293// //               return;
4294// //
4295// //           if( data.URI )
4296// //               el = DataLayer.update( concept, data.URI, el );
4297// //           else
4298// //               DataLayer.set( concept, el, el.URI );
4299// //
4300// //           result[ result.length ] = el;
4301// //           DataLayer.broadcast( concept );
4302// //     });
4303// //       };
4304// //
4305// //       $.ajax({
4306// //         'async': ( !wait ),
4307// //         'url': url,
4308// //         'type': type,
4309// //         'success': callback,
4310// //         'dataType': 'json',
4311// //         'data': data/*,
4312// //         'processData': false*/
4313// //     });
4314// //
4315// //       return( notArray ? result[0] || false : result );
4316// //     },
4317//     
4318//     
4319//     generateURI: function( concept ){
4320//       
4321//      return this.URI( concept, this.generateId( concept ), "javascript" );
4322//
4323//     },
4324//     
4325//
4326//     broadcast: function( concept, status, diff ){
4327//
4328//      if( this.listeners[ concept ] )
4329//          for( var i = 0;
4330//              i < this.listeners[ concept ].length;
4331//              this.listeners[ concept ][ i++ ]( status, diff ) );
4332//     },
4333//
4334//     listen: function( concept, listener ){
4335//
4336//      this.register( "listeners", concept, listener );
4337//
4338//     },
4339//
4340//     codec: function( concept, namespace, codec ){
4341//
4342//      if( codec.encoder )
4343//          this.encoder( concept, namespace, codec.encoder );
4344//      if( codec.decoder )
4345//          this.decoder( concept, namespace, codec.decoder );
4346//      if( codec.criteria )
4347//          this.register( "criterias", concept + ":" + namespace, codec.criteria );
4348//
4349//     },
4350//
4351//     encoder: function( concept, namespace, encoder ){
4352//
4353//      this.register( "encoders", concept + ":" + namespace, encoder );
4354//
4355//     },
4356//
4357//     encode: function( encoder, data, filter ){
4358//
4359//      if( this.encoders[ encoder ] )
4360//          for( var i = 0;
4361//              i < this.encoders[ encoder ].length;
4362//              data = this.encoders[ encoder ][ i++ ]( data, filter ) );
4363//
4364//      return( data );
4365//     },
4366//
4367//     decoder: function( concept, namespace, decoder ){
4368//
4369//      this.register( "decoders", concept + ":" + namespace, decoder );
4370//
4371//     },
4372//
4373//     decode: function( decoder, data ){
4374//
4375//      if( this.decoders[ decoder ] )
4376//          for( var i = 0;
4377//              i < this.decoders[ decoder ].length;
4378//              data = this.decoders[ decoder ][ i++ ]( data ) );
4379//
4380//      return( data );
4381//     },
4382//
4383//     criteria: function( codec, filter ){
4384//
4385//      if( this.criterias[ codec ] )
4386//          for( var i = 0;
4387//              i < this.criterias[ codec ].length;
4388//              filter = this.criterias[ codec ][ i++ ]( filter ) );
4389//
4390//      return( filter );
4391//
4392//     },
4393//
4394//     register: function( kind, concept, deployable ){
4395//
4396//       if( arguments.length < 3 )
4397//       {
4398//        deployable = concept;
4399//        concept = kind;
4400//        kind = 'global';
4401//       }
4402//
4403//       if( !this[ kind ][ concept ] )
4404//          this[ kind ][ concept ] = [];
4405//
4406//      this[ kind ][ concept ][ this[ kind ][ concept ].length ] = deployable;
4407//
4408//     },
4409//     
4410//     start: function(){
4411//
4412//      var timer = function(){
4413//
4414//            setTimeout( timer, 1 );
4415//
4416//            var now = parseInt( $.now() / 1000 );
4417//
4418//            var tasks = DataLayer.tasks[ now ];
4419//
4420//            if( !tasks ) return;
4421//
4422//            for( var i = 0; i < tasks.length; i++ )
4423//            {
4424//                var result = tasks[i].task( now );
4425//
4426//                if( tasks[i].factor )
4427//                DataLayer.schedule( tasks[i].task, tasks[i].factor );
4428//            }
4429//       
4430//            delete DataLayer.tasks[ now ];
4431//      };
4432//
4433//      setTimeout( timer, 1 );
4434//     },
4435//     
4436//     task: function( timestamp, task, factor )
4437//     {
4438//      if( !this.tasks[ timestamp ] )
4439//          this.tasks[ timestamp ] = [];
4440//
4441//      this.tasks[ timestamp ][ this.tasks[ timestamp ].length ] = { task: task, factor: factor || false };
4442//     },
4443//
4444//     schedule: function( task, time ){
4445//
4446//      time = time || 1;
4447//     
4448//      var index = parseInt( $.now() / 1000 ) + time;
4449//
4450//      this.task( index, task, time );
4451//     },
4452//     
4453//     poll: function( concept, time ){
4454//       
4455//       this.schedule( function( now ){
4456//   
4457//        DataLayer.commit( concept );
4458//
4459//      }, time || 5 );
4460//     },
4461//     
4462//     init: function(){
4463//       
4464//      this.counter = parseInt( this.get( ":counter", false ) ) || 0;
4465//
4466//      if( !this.dispatchPath )
4467//          this.dispatchPath = "../../";
4468//
4469//      if( !this.templatePath )
4470//          this.templatePath = "";
4471//
4472//      if( !this.basePath )
4473//          this.basePath = this.dispatchPath + "REST.php?q=";
4474//
4475//      this.schedule( function( now ){
4476//
4477//          DataLayer.flush();
4478//
4479//      });
4480//
4481//      this.start();
4482//     }
4483// }
4484//
4485// // the re-usable constructor function used by clone().
4486// function Clone() {}
4487//
4488// //Recursion Helper
4489// function RecursionHelper(){ this.clear(); };
4490//
4491// RecursionHelper.prototype = {
4492//   
4493//      constructor: RecursionHelper,
4494//
4495//      // copiedObjects keeps track of objects already copied by this
4496//      // deepCopy operation, so we can correctly handle cyclic references.
4497//      copiedObjects: [],
4498//
4499//      depth: 0,
4500//
4501//      maxDepth: 256,
4502//
4503//      //reset the recursion helper cache
4504//      clear: function(){
4505//              this.copiedObjects = [];
4506//              this.depth = 0;
4507//      },
4508//
4509//      // add an object to the cache.  No attempt is made to filter duplicates;
4510//      // we always check getCachedResult() before calling it.
4511//      cacheResult: function(source, result) {
4512//              this.copiedObjects.push([source, result]);
4513//      },
4514//
4515//      // Returns the cached copy of a given object, or undefined if it's an
4516//      // object we haven't seen before.
4517//      getCachedResult: function(source) {
4518//
4519//              for ( var i=0; i<this.copiedObjects.length; i++ ) {
4520//                      if ( this.copiedObjects[i][0] === source ) {
4521//                              return this.copiedObjects[i][1];
4522//                      }
4523//              }
4524//
4525//              return undefined;
4526//      }
4527// };
4528//
4529// // Generic Object copier
4530// // the ultimate fallback DeepCopier, which tries to handle the generic case.  This
4531// // should work for base Objects and many user-defined classes.
4532// DataLayer.registerComparator({
4533//      can: function(source) { return true; },
4534//
4535//      create: function(source) {
4536//              if ( source instanceof source.constructor ) {
4537//                      return DataLayer.clone(source.constructor.prototype);
4538//              } else {
4539//                      return {};
4540//              }
4541//      },
4542//
4543//      populate: function(deepCopy, source, result) {
4544//              for ( var key in source ) {
4545//                      if ( source.hasOwnProperty(key) ) {
4546//                              result[key] = deepCopy(source[key], result[key]);
4547//                      }
4548//              }
4549//              return result;
4550//      }
4551// });
4552//
4553// // Array copier
4554// DataLayer.registerComparator({
4555//      can: function(source) {
4556//              return ( source instanceof Array );
4557//      },
4558//
4559//      create: function(source) {
4560//              return new source.constructor();
4561//      },
4562//
4563//      populate: function(deepCopy, source, result) {
4564//              for ( var i=0; i<source.length; i++) {
4565//                      result.push( deepCopy(source[i], result[i]) );
4566//              }
4567//              result =  DataLayer.unique( result )
4568//              return result;
4569//      }
4570// });
4571//
4572// // Date copier
4573// DataLayer.registerComparator({
4574//      can: function(source) {
4575//              return ( source instanceof Date );
4576//      },
4577//
4578//      create: function(source) {
4579//              return new Date(source);
4580//      }
4581// });
4582//
4583// // HTML DOM Node copier
4584// DataLayer.registerComparator({
4585//
4586//      // function to detect Nodes.  In particular, we're looking
4587//      // for the cloneNode method.  The global document is also defined to
4588//      // be a Node, but is a special case in many ways.
4589//      can: function(source) {
4590//       
4591//        if ( window.Node ) {
4592//                return source instanceof Node;
4593//        } else {
4594//                // the document is a special Node and doesn't have many of
4595//                // the common properties so we use an identity check instead.
4596//                if ( source === document ) return true;
4597//                return (
4598//                        typeof source.nodeType === 'number' &&
4599//                        source.attributes &&
4600//                        source.childNodes &&
4601//                        source.cloneNode
4602//                );
4603//        }
4604//       },
4605//
4606//       create: function(source) {
4607//            // there can only be one (document).
4608//            if ( source === document ) return document;
4609//
4610//            // start with a shallow copy.  We'll handle the deep copy of
4611//            // its children ourselves.
4612//            return source.cloneNode(false);
4613//       },
4614//       
4615//       diff: function(base, source){
4616//     
4617//       },
4618//
4619//       populate: function(deepCopy, source, result) {
4620//            // we're not copying the global document, so don't have to populate it either.
4621//            if ( source === document ) return document;
4622//
4623//            // if this Node has children, deep copy them one-by-one.
4624//            if ( source.childNodes && source.childNodes.length ) {
4625//                    for ( var i=0; i<source.childNodes.length; i++ ) {
4626//                            var childCopy = deepCopy(source.childNodes[i], result.childNodes[i] || false );
4627//                            result.appendChild(childCopy);
4628//                    }
4629//            }
4630//              return result;
4631//       }
4632// });
4633//
4634// DataLayer.init();
4635//
4636// // setTimeout(function(){
4637// // 
4638// //     
4639// //
4640// // }, 1000 );
4641//
4642// // var DataLayer = {
4643// //
4644// //     get: function( concept, filter ){
4645// //
4646// //   var data = this.storage.get( concept );
4647// //
4648// //   if( !filter )
4649// //       return( data );
4650// //
4651// //   return this.filter( data, filter );
4652// //     },
4653// //     
4654// //     filter:function( data, filter ){
4655// //       
4656// //   if( filter.charAt )
4657// //       filter = { URI: filter };
4658// //   
4659// //   var filtered = [];
4660// //
4661// //   $.each(data, function(i, obj){
4662// //     
4663// //       for( var attr in filter )
4664// //           if( filter[attr] !== obj[attr] )
4665// //               return( true );
4666// //
4667// //       filtered[i] = obj;
4668// //   });
4669// //
4670// //   return( filtered );
4671// //     },
4672// //
4673// //     find: function( concept, filter, callback ){
4674// //
4675// //   var data = this.get( concept, filter );
4676// //
4677// //   if( data )
4678// //       return callback( data );
4679// //
4680// //   //TODO: register callback like a weak listener
4681// //
4682// // //        $.ajax({
4683// // //              type: 'GET',
4684// // //              data: $.param( filter ),
4685// // //              success: callback, 
4686// // //              url: BASE_PATH + filter.URI || concept
4687// // //        });
4688// //   this.report( concept, filter );
4689// //     },
4690// //
4691// //     put: function( concept, data, filter ){
4692// //
4693// //   var beforeDiff = this.store( concept, $.extend({},data) );
4694// //
4695// //   this.report( concept, data, filter, beforeDiff );
4696// //     },
4697// //     
4698// //     
4699// //     /*var data = {
4700// //                   startTime: $.now(),
4701// //                   endTime: $.now() + 1800000,
4702// //                   summary: "meu querido evento",
4703// //                   description: "desc do evento",
4704// //                   location: "prognus software livre",
4705// //                   class: 1,
4706// //                   calendar: 1,
4707// //                   category: 1,
4708// //                   participants: [ {
4709// //                                      user: { isExternal: true, mail: "user7@prognus.org", name: "user7" }
4710// //                                 },{
4711// //                                      user: "1003"
4712// //                                 } ]
4713// //
4714// //             };*/
4715// //     
4716// //
4717// //     merge:function( data, target ){
4718// //       
4719// //   var diff = { New: {}, Update:{}, Delete: {} };
4720// //       
4721// //   for( var key in data )
4722// //   {
4723// //       if( !target[ key ] )
4724// //           diff.New[ key ] = target[ key ] = data[ key ];
4725// //
4726// //       
4727// //     
4728// //   }
4729// //       
4730// //     }
4731// //
4732// //     store: function( concept, data, filter ){
4733// //
4734// //   if( !data.spline )
4735// //       data = [ data ];
4736// //
4737// //   var target = this.storage.get( concept );
4738// //   
4739// //   var diff = { New: {}, Update:{}, Delete: {} };
4740// //
4741// //   for( var i = 0; i < data.length; i++ )
4742// //   {
4743// //       if( data[i].URI && target[ data[i].URI ] )
4744// //       {
4745// //           diff.Update[ data[i].URI ] = this.merge( target[ data[i].URI ], data[i] );
4746// //       }
4747// //       else
4748// //       {
4749// //           diff.New[] = data[i];
4750// //       }
4751// //   }
4752// //
4753// //   
4754// //
4755// //   this.broadcast( concept, data );
4756// //
4757// //   if( filter )
4758// //       target = this.filter( target, filter );
4759// //
4760// //   if( target )
4761// //       data = $.extend( target, data );
4762// //
4763// //   this.storage.set( concept, data );
4764// //
4765// // //        return;
4766// //     },
4767// //     
4768// //     set: function( concept, data, filter ){
4769// //
4770// //       
4771// //
4772// //     },
4773// //
4774// //     post: function( concept, data, filter, isNew ){
4775// //
4776// //   var callback = function(  ){ DataLayer.store( concept, data, filter ) };
4777// //
4778// //   //TODO: register callback like a weak listener
4779// //
4780// //   this.report( concept, data, filter, isNew );
4781// //     },
4782// //     
4783// //     report: function( concept, filter, postData, isNew ){
4784// //       
4785// //   $.ajax({
4786// //           type: postData ? isNew ? 'POST' : 'PUT' : 'GET',
4787// //           data: postData || $.param( filter ),
4788// //           success: function( data ){ DataLayer.broadcast( concept ) },
4789// //           url: BASE_PATH + filter.URI || concept
4790// //     });
4791// //     },
4792// //     
4793// //     del:function( concept, filter ){
4794// //
4795// //       
4796// //
4797// //     }
4798// //     
4799// //     broadcast: function( concept, data ){
4800// //
4801// //   
4802// //
4803// //     },
4804// //
4805// //     pool: function(){
4806// //       
4807// //     },
4808// //
4809// //     refresh: function(){
4810// //       
4811// //     }
4812// // };
4813//
4814// //
4815// // DataLayer = {
4816// //   
4817// //     get: function( concept, filter ){
4818// //
4819// //   var data = this.storage.get( concept );
4820// //
4821// //   if( !filter )
4822// //       return( data );
4823// //
4824// //   if( filter.charAt )
4825// //       filter = { URI: filter };
4826// //   
4827// //   var filtered = [];
4828// //
4829// //   $.each(data, function(i, obj){
4830// //     
4831// //       for( var attr in filter )
4832// //           if( filter[attr] !== obj[attr] )
4833// //               return( true );
4834// //
4835// //       filtered[i] = obj;
4836// //   });
4837// //
4838// //   return( filtered );
4839// //     },
4840// //
4841// //     find: function( concept, filter, callback ){
4842// //
4843// //   var data = this.get( concept, filter );
4844// //
4845// //   if( data )
4846// //       return callback( data );
4847// //
4848// //    $.ajax({
4849// //         type: 'GET',
4850// //         data: $.param( filter ),
4851// //         success: callback, 
4852// //         url: filter.URI || concept
4853// //   });
4854// //     },
4855// //
4856// //     put: function( concept, data, filter ){
4857// //
4858// //   var target = this.get( concept, filter );
4859// //
4860// //   if( target )
4861// //       data = $.extend( target, data );
4862// //       
4863// //   this.storage.set( concept, data );
4864// //   
4865// //   //diff
4866// //     },
4867// //     
4868// //     post: function( concept, data, filter ){
4869// //
4870// //   
4871// //
4872// //     },
4873// //     
4874// //     pool: function(){
4875// //       
4876// //     },
4877// //     
4878// //     queue: function(){
4879// //       
4880// //     },
4881// //     
4882// //     dequeue: function(){
4883// //       
4884// //     },
4885// //     
4886// //     refresh: function(){
4887// //       
4888// //     }
4889// // }
4890//
4891// // var DataLayer = {
4892//   
4893// //       cache: {},
4894//   
4895// //       get: function( concept, location ){
4896//     
4897//         /* if( location )
4898//          {*/
4899// //           var schema = $.data( this.cache, concept + ':schema' );
4900// //           var uri = [];
4901// //
4902// //           $.each( schema, function( i, addrs ){
4903// //                 uri[ uri.length ] = location[addrs];
4904// //           });
4905//
4906//              /*var filter = [], result = false;
4907//
4908//              while( !(result = $.data( this.cache, uri.join( '.' ) )) || !(uri = uri.join('.')) )
4909//                filter[ filter.length ] = uri.pop();
4910//   
4911//              if( !filter.length )
4912//              {
4913//                  var indexes = $.data( this.cache, uri + ':indexes' );
4914//
4915//                  if( indexes )
4916//                      Array.prototype.concat.apply( result, indexes );
4917//                 
4918//                  return( result );
4919//              }
4920//
4921//              for( var i = 0; i < result.length; i++ )
4922//              {
4923//                 
4924//              }
4925//
4926//              if( result.length )
4927//                  return( result );
4928//          }*/
4929//
4930// //       var data = $.data( this.cache, concept );
4931//
4932// //       if( !data )
4933// //           $.ajax( );
4934//
4935// //       return( data );
4936// //       },
4937//       
4938// //       data: function(){
4939// //
4940// //     
4941// //
4942// //       }
4943// //       
4944// //       search: function( concept, filter ){
4945// //
4946// //     var schema = $.data( this.cache, concept + ':schema' );
4947// //     var uri = [];
4948// //
4949// //     $.each( schema, function( i, addrs ){
4950// //           uri[ uri.length ] = location[addrs];
4951// //     });
4952// //       }
4953// //       put: function( concept, data, location ){
4954//
4955// //       if( location )
4956// //       {
4957// //           var schema = $.data( this.cache, concept + ':schema');
4958// //           var uri = [];
4959//
4960// //           $.each( schema, function( i, addrs ){
4961// //                 uri[ uri.length ] = location[addrs];
4962// //           });
4963//
4964// //           var result = false, filter = [];
4965//
4966// //           while( !(result = $.data( this.cache, uri.join('.')) )
4967// //               filter[ filter.length ] = uri.pop();
4968//
4969// //           $.data( this.cache, '
4970//
4971// //       }
4972//
4973// //           var model = this.storage.get( concept );
4974// //
4975// //           $.each( model, function( i, o ){
4976// //               $.each( location, function( ii, attr ){
4977// //                    if( o[ii] === attr )
4978// //                       return( false );
4979// //               });
4980// //           });
4981//
4982// //       return $.data( this.cache, concept, data );
4983//
4984// //       },
4985// //       del: function( concept, location ){
4986// //
4987// //       if( location )
4988// //       {
4989// //           var schema = $.data( this.cache, 'concepts', concept );
4990// //           var uri = [];
4991// //
4992// //           $.each( schema, function( i, addrs ){
4993// //                 uri[ uri.length ] = location[addrs];
4994// //           });
4995// //
4996// //           concept = uri.join( '.' );
4997//
4998// //           var model = this.storage.get( concept );
4999// //
5000// //           $.each( model, function( i, o ){
5001// //               $.each( location, function( ii, attr ){
5002// //                    if( o[ii] === attr )
5003// //                       return( false );
5004// //               });
5005// //           });
5006// //       }
5007// //       
5008// //   
5009// //       $.removeData( this.cache, concept );
5010// //       }
5011// // }
Note: See TracBrowser for help on using the repository browser.