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

Revision 5908, 121.9 KB checked in by natan, 12 years ago (diff)

Ticket #2603 - Corrigir a camada de sincronizacao - Correcao no remove do cache do cliente

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