source: trunk/prototype/app/datalayer.js @ 5341

Revision 5341, 56.3 KB checked in by wmerlotto, 12 years ago (diff)

Ticket #2434 - Commit inicial do novo módulo de agenda do Expresso - expressoCalendar

  • 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 = /^:/;
6// cached_urls = {};
7
8$.ajaxPrefilter(function( options, originalOptions, jqXHR ){
9
10      if( options.url != 'undefined' && internalUrl.test( options.url ) ){
11
12//        if( !cached_urls[options.url] )
13//            return;
14//        alert( options.url + " dentro" );
15          jqXHR.abort();
16
17          var callback = ( options.success || options.complete || $.noop );
18
19          switch( options.type.toUpperCase() )
20          {
21            case 'GET':
22                  return callback( DataLayer.get( options.url, /*false,*/ options.data ) );
23
24            case 'POST':
25                  return callback( DataLayer.put( options.url, options.data ) );
26          }
27
28          //return( false );
29
30//        options.url = params[1];
31//        options.data = ( options.data || "" ) + "&" + params[2];
32      }
33
34});
35
36// $("a").live("click", function( event ){
37//
38//     event.preventDefault();
39//
40//     $.ajax({
41//
42//     
43//
44//     });
45//
46// });
47
48$("form").live( "submit", function( event ){
49
50    var $this = $(this), action = $this.attr('action'), res = false,
51   
52    method = $this.attr( 'method' ),
53   
54    fileInputs = $this.find('input[type="file"]');
55   
56    if( fileInputs.length && !$this.is('[enctype="multipart/form-data"]') )
57    {
58        event.preventDefault();
59
60        DataLayer.send( action,
61                        [ method, 'iframe json' ], {},
62                        //TODO: check the type for conversion
63                        DataLayer.receive,
64                        false, { 'formData': $this.serializeArray(),  'fileInput': fileInputs } );
65
66        return( false );
67    }
68   
69    if( res = internalUrl.exec( action ) )
70    {
71        event.preventDefault();
72
73        var data = DataLayer.form( this );
74       
75        switch( method.toUpperCase() )
76        {
77          case 'GET':
78                DataLayer.get( res[0], data );
79
80          case 'POST':
81        DataLayer.put( res[1], data );
82        }
83
84        return( false );
85    }
86
87    return( true );
88});
89
90this.storage = new $.store();
91
92DataLayer = {
93
94    links: {},
95    concepts: {},
96    listeners: {},
97    encoders: {},
98    decoders: {},
99    templates: {},
100    criterias: {},
101    tasks: [],
102
103    render: function( templateName, data, filter, formatter, force ){
104
105        if( $.isFunction( filter ) )
106        {
107            force = formatter;
108            formatter = filter;
109            filter = false;
110        }
111
112        if( typeof data === "string" )
113        {
114            data = this.get( data, filter, force ) || {};
115        }
116       
117        var formatting = function( template ){
118
119              if( template === false ) return( false );
120
121              if( template )
122                  DataLayer.templates[ templateName ] = new EJS({ text: template, cache: false });
123
124              var html = DataLayer.templates[ templateName ].render( { data: data } );
125
126              if( !formatter )
127                  return( html );
128
129              return formatter( html );
130        }
131
132        if( this.templates[ templateName ] )
133        {
134            return formatting();
135        }
136
137        return this.send( DataLayer.templatePath + templateName, 'get', false, formatting, !!!formatter );
138    },
139   
140    send: function( url, type, data, callback, sync, extraOptions ){
141     
142          var result = false, fired = false;
143     
144          var envelope = {
145
146              'async': ( typeof sync !== "undefined" ? !sync : !!callback ),
147              'url': url,
148              'success': function( dt, textStatus, jqXHR ){
149
150                    if( callback )
151                    {
152                        fired = true;
153                        result = callback( dt, textStatus, jqXHR );
154                    }
155                    else
156                        result = dt;
157
158                },
159              'complete': function( jqXHR, textStatus ){
160
161                  if( !fired && callback )
162                      result = callback( false, textStatus, jqXHR );
163
164              },
165
166              'type': $.isArray( type ) ? type[0] : type,
167              'data': data
168
169            };
170
171          if( $.isArray( type ) && type[1] )
172              envelope['dataType'] = type[1];
173
174          if( extraOptions )
175              envelope = $.extend( envelope, extraOptions );
176
177          $.ajax( envelope );
178     
179          return( result );
180    },
181   
182    dispatch: function( dispatcher, data, callback, isPost, dataType ){
183     
184      return this.send( this.dispatchPath + dispatcher + ".php",
185                        [ ( isPost ? 'post' : 'get' ), dataType || 'json' ],
186                        data,
187                        callback );
188
189//       $.ajax({
190//            'async': !!callback,
191//            'url': this.dispatchPath + dispatcher + ".php",
192//            'type': ( isPost ? 'post' : 'get' ),
193//            'dataType': 'json',
194//            'data': data,
195//            'success': function( dt, textStatus, jqXHR ){
196//
197//                  if( callback )
198//                  {
199//                      fired = true;
200//                      callback( dt, textStatus, jqXHR );
201//                  }
202//                  else
203//                      result = dt;
204//
205//              },
206//            'complete': function( jqXHR, textStatus ){
207//
208//                if( !fired && callback )
209//                    callback( false, textStatus, jqXHR );
210//
211//            }/*,
212//            'processData': false*/
213//        });
214
215      //return( result );
216    },
217
218    form: function( target ){
219
220        var params = {}, $this = $(target);
221
222        if( !$this.is( "form" ) )
223            $this = $this.parents( "form" );
224
225        $.each( $this.serializeArray(), function( i, el ){
226
227            if( newName = arrayName.exec( el.name ) )
228                el.name = newName[1];
229            else if( !params[ el.name ] )
230                return( params[ el.name ] = el.value );
231
232            params[ el.name ] = params[ el.name ] || [];
233
234            if( $.type(params[ el.name ]) !== "array" )
235                params[ el.name ] = [ params[ el.name ] ];
236
237            params[ el.name ].push( el.value );
238        });
239
240//      alert(dump(params));
241
242        return this.decode( $this.attr( "action" ), params );
243    },
244
245    blend: function( action, data ){
246
247//      if( notArray = (!$.isArray(data)) )
248//          data = [ data ];
249
250        var form = $('form[action="'+action+'"]');
251
252        form.get(0).reset();
253
254        var named = form.find( 'input[name]' );
255
256        for( var name in data )
257        {
258            named.filter( '[name="'+name+'"]' ).val( data[name] );
259        }
260    },
261
262 
263   
264    put: function( concept, filter, data, oneSide ){
265     
266      ///////////////////////////// normalize ////////////////////////////////
267        if( arguments.length == 2 )
268        {
269            data = filter;
270            filter = false;
271        }
272        if( typeof data === "undefined" ||
273            $.type(data) === "boolean" )
274        {
275            oneSide = data;
276            data = filter;
277            filter = false;
278        }
279       
280        if( !concept || !data )
281            return( false );
282
283        var decoder = "", id = false, bothSides = (typeof oneSide === "undefined"), notArray, res;
284       
285        if( $.type(filter) === "string" )
286        {
287            id = filter;
288            filter = false;
289        }
290
291        if( id )
292            data.id = id;
293
294        if( notArray = ( $.type( data ) !== "array" ) )
295            data = [ data ];
296
297        if( res = internalUrl.exec( concept ) )
298        {
299            //TODO: verificar se a decodificaçao deve ser feita em cada item do array
300            data = this.decode( concept, data );
301            concept = res[1];
302            decoder = res[2];
303        }
304
305      ////////////////////////////////////////////////////////////////////////
306
307        if( bothSides || !oneSide )
308        {
309            var result = false, links = this.links( concept ),
310            current = this.check( concept ) || {}, ids = [];
311
312            for( var i = 0; i < data.length; i++ )
313            {
314                var key = ids[ ids.length ] = data[i].id || this.generateId( concept ), updateSet = {};
315
316                ////////////////////////////// linkage /////////////////////////////////   
317                for( var link in links )
318                {
319                    if( data[i][link] )
320                    {
321                        var isConcept = false;
322                     
323                        if( isConcept = this.isConcept( concept, link ) )
324                            data[i][link] = [ data[i][link] ];
325
326                        var _this = this;
327
328                        $.each( data[i][link], function( ii, el ){
329
330                                var isRef = false;
331
332                                if( isRef = ($.type(el) === "string") )
333                                    el = { id: el };
334
335                                var nestedLinks = _this.links( links[link], true );
336                               
337                                if( isConcept )
338                                {
339                                    el[ nestedLinks[concept] ] = el[ nestedLinks[concept] ] || [];
340                                    el[ nestedLinks[concept] ].push( key );
341                                }
342                                else
343                                    el[ nestedLinks[concept] ] = key;
344
345                                if( isRef && ( !current[ key ] || !current[ key ][ link ] ||
346                                               (isConcept ? current[ key ][ link ] !== el.id : !$.inArray( el.id, current[ key ][ link ] )) ) )
347                                {
348                                    updateSet[ links[link] ] = updateSet[ links[link] ] || [];
349                                    updateSet[ links[link] ].push( el );
350                                }
351                                else if( !isRef )
352                                    data[i][link][ii] = _this.put( links[link], el, oneSide );
353                            });
354
355                        if( isConcept )
356                            data[i][link] = data[i][link][0];
357                    }
358                }
359                //////////////////////////////////////////////////////////////////////////
360
361                if( data[i].id )
362                    data[i] = this.merge( current[ data[i].id ], data[i] );
363
364                 current[ key ] = data[i];
365
366                if( bothSides )
367                  this.report( concept, key, data[i] );
368            }
369
370            this.store( concept, current );
371
372            for( var setKey in updateSet )
373            {
374                if( bothSides )
375                    for( var i = 0; i < updateSet[ setKey ].length; i++ )
376                      this.report( setKey, updateSet[ setKey ][i].id, updateSet[ setKey ][i] );
377                   
378                DataLayer.put( setKey, updateSet[ setKey ], false );
379            }
380        }
381
382        if( oneSide )
383            this.commit( concept, ids/*, true */);
384
385        this.broadcast( concept, oneSide ? 'server' : bothSides ? 'serverclient' : 'client', true );
386
387        return( notArray ? ids[0] : ids );
388
389    },
390   
391    remove: function( concept, id, oneSide ){
392     
393        var bothSides = (typeof oneSide === "undefined");
394
395        if( bothSides || !oneSide )
396            this.del( concept, id );
397
398        if( bothSides )
399            this.report( concept, id, false );
400        if( oneSide )
401            this.commit( concept, id );
402
403        this.broadcast( concept, oneSide ? 'server' : bothSides ? 'serverclient' : 'client', false );
404    },
405   
406    report: function( concept, id, data )
407    {     
408        var current = this.check( ':current', concept ) || {};
409
410        if( !current[ id ] )
411            current[ id ] = this.check( concept, id ) || {};
412       
413        this.store( ':current', concept, current[ id ] );
414
415        var diff = this.diff( current[ id ], data );
416
417        var diffs = this.check( ':diff', concept ) || {};
418
419        if( diffs[ id ] )
420            diff = this.merge( diffs[ id ], diff );
421
422        if( !$.isEmptyObject( diff ) )
423        diffs[ id ] = diff;
424
425        this.store( ':diff', concept, diffs );
426    },
427
428//     enqueue: function( queueName, concept, id, data ){
429//
430//      var queue = this.check( ':' + queueName, concept ) || {};
431//
432//
433//     },
434//     
435//     dequeue: function( queueName, concept, id ){
436//
437//     
438//
439//     },
440   
441   
442   
443    rollback: function( concept, ids ){
444     
445        var queue = this.prepareQ( 'current', concept, ids );
446
447        ids = [];
448
449        for( var id in queue )
450        {
451             this.put( concept, id, queue[id], false );
452
453             ids[ ids.length ] = id;
454        }
455
456        this.clearQ( concept, ( ids.length ? ids : false ) );
457
458        this.broadcast( concept, 'revert' );
459     
460    },
461   
462    prepareQ: function( queueName, concept, ids ){
463     
464      var notArray = false;
465     
466      if( notArray = ($.type(concept) !== "array") )
467          concept = [ concept ];
468     
469      var q = {};
470     
471      for( var i = 0; i < concept.length; i++ )
472      {
473          var queue = this.check( ':' + queueName, concept[i] || false );
474         
475          if( !queue ) continue;
476
477          if( ids )
478          {
479              if( $.type(ids) !== "array" )
480                  ids = [ ids ];
481
482              var filtered = {};
483
484              for( var ii = 0; ii < ids.length; ii++ )
485              {
486                  filtered[ ids[ii] ] = queue[ ids[ii] ];
487              }
488
489              queue = filtered;
490          }
491
492          q[ concept[i] ] = queue;
493      }
494     
495      return( notArray ? q[ concept[0] ] : q );
496    },
497   
498    clearQ: function( concept, ids ){
499     
500//              var current = this.check( ':current', concept || false );
501        var diffs = this.check( ':diff', concept || false );
502
503        if( !ids )
504           /* current =*/ diffs = {};
505        else
506        {
507            if( notArray = ($.type(ids) !== "array") )
508              ids = [ ids ];
509
510            for( var i = 0; i < ids.length; i++ )
511            {
512//              delete current[ ids[i] ];
513                delete diffs[ ids[i] ];
514            }
515        }
516
517//      this.store( ':current', concept, current );
518        this.store( ':diff', concept, diffs );
519    },
520
521    commit: function( concept, ids, callback ){
522     
523        var queue = this.prepareQ( 'diff', concept, ids );
524
525        this.sync( queue, !$.isArray(concept) && concept || false, callback );
526    },
527   
528    sync: function( queue, concept, callback ){
529
530        if( !queue || $.isEmptyObject( queue ) )
531            return;
532
533        if( concept )
534        {
535          var helper = {};
536          helper[concept] = queue;
537          queue = helper;
538        }
539
540        var data = {}, URIs = {};
541
542        for( var concept in queue )
543            for( var id in queue[concept] )
544            {
545                data[ this.URI( concept, id ) ] = queue[concept][id];
546                URIs[ this.URI( concept, id ) ] = { concept: concept, id: id };
547            }
548
549        if( $.isEmptyObject( data ) )
550            return;
551
552        this.dispatch( "Sync", data, function( data, status, jqXHR ){
553
554//          switch( status )
555//          {
556//            case "error":
557//            case "parsererror":
558//              return DataLayer.rollback( concept, URI );
559//            case "success":
560//              return DataLayer.commit();
561//            case "timeout":
562//            case "notmodified":
563//          }
564
565            var received = DataLayer.receive( data );
566
567            for( var URI in URIs )
568                if( typeof received[URI] !== "undefined" )
569                    DataLayer.clearQ( URIs[URI].concept, URIs[URI].id );
570
571            if( callback )
572                callback( received );
573
574//          for( var URI in data )
575//          {
576//              var parsed = DataLayer.parseURI( URI ),
577//   
578//              concept = parsed[1], id = parsed[3];
579//
580//              if( $.type(data[URI]) === "string" )
581//              {
582//                //TODO:threat the exception thrown
583//                DataLayer.rollback( concept, id );
584//                delete URIs[ URI ];
585//                continue;
586//              }
587//
588//              if( data[URI] === false ){
589//                DataLayer.remove( concept, id, false );
590//                continue;
591//              }
592//
593//              if( id !== data[URI].id )
594//                DataLayer.move( concept, id, data[URI].id );
595//             
596//              DataLayer.put( concept, id, data[URI], false );
597//          }
598//         
599//          for( var URI in URIs )
600//               DataLayer.clearQ( URIs[URI].concept, URIs[URI].id );
601//         
602//          if( callback )
603//              callback();
604
605        }, true );
606
607    },
608   
609    receive: function( data ){
610     
611        var received = {};
612       
613            for( var URI in data )
614            {
615                var parsed = DataLayer.parseURI( URI ),
616   
617            concept = parsed[4], id = parsed[5];
618
619            received[ URI ] = data[ URI ];
620
621                if( $.type(data[URI]) === "string" )
622                {
623                  //TODO:threat the exception thrown
624                  DataLayer.rollback( concept, id );
625                  continue;
626                }
627
628                if( data[URI] === false ){
629                  DataLayer.remove( concept, id, false );
630                  continue;
631                }
632
633                if( id !== data[URI].id )
634                  DataLayer.move( concept, id, data[URI].id );
635               
636                DataLayer.put( concept, id, data[URI], false );
637            }
638           
639        return( received );
640           
641    },
642
643   
644
645    merge: function( current, data ){
646     
647        return this.copy(  data, current );
648
649//      return $.extend( current, data );
650
651    },
652   
653    // clone objects, skip other types.
654    clone: function(target) {
655            if ( typeof target == 'object' ) {
656                    Clone.prototype = target;
657                    return new Clone();
658            } else {
659                    return target;
660            }
661    },
662     
663    // Shallow Copy
664    shallowCopy: function(target) {
665            if (typeof target !== 'object' ) {
666                    return target;  // non-object have value sematics, so target is already a copy.
667            } else {
668                    var value = target.valueOf();
669                    if (target != value) {
670                            // the object is a standard object wrapper for a native type, say String.
671                            // we can make a copy by instantiating a new object around the value.
672                            return new target.constructor(value);
673                    } else {
674                            // ok, we have a normal object. If possible, we'll clone the original's prototype
675                            // (not the original) to get an empty object with the same prototype chain as
676                            // the original.  If just copy the instance properties.  Otherwise, we have to
677                            // copy the whole thing, property-by-property.
678                            if ( target instanceof target.constructor && target.constructor !== Object ) {
679                                    var c = clone(target.constructor.prototype);
680     
681                                    // give the copy all the instance properties of target.  It has the same
682                                    // prototype as target, so inherited properties are already there.
683                                    for ( var property in target) {
684                                            if (target.hasOwnProperty(property)) {
685                                                    c[property] = target[property];
686                                            }
687                                    }
688                            } else {
689                                    var c = {};
690                                    for ( var property in target ) c[property] = target[property];
691                            }
692                           
693                            return c;
694                    }
695            }
696    },
697
698    // entry point for deep copy.
699    // source is the object to be deep copied.
700    // depth is an optional recursion limit. Defaults to 256.
701    // deep copy handles the simple cases itself: non-objects and object's we've seen before.
702    // For complex cases, it first identifies an appropriate DeepCopier, then delegate the details of copying the object to him.
703    copy: function(source, result, depth) {
704     
705            // null is a special case: it's the only value of type 'object' without properties.
706            if ( source === null ) return null;
707
708            // All non-objects use value semantics and don't need explict copying.
709            if ( typeof source !== 'object' ) return source;
710
711            if( !depth || !(depth instanceof RecursionHelper) ) depth = new RecursionHelper(depth);
712
713            var cachedResult = depth.getCachedResult(source);
714
715            // we've already seen this object during this deep copy operation
716            // so can immediately return the result.  This preserves the cyclic
717            // reference structure and protects us from infinite recursion.
718            if ( cachedResult ) return cachedResult;
719
720            // objects may need special handling depending on their class.  There is
721            // a class of handlers call "DeepCopiers"  that know how to copy certain
722            // objects.  There is also a final, generic deep copier that can handle any object.
723            for ( var i=0; i<this.comparators.length; i++ ) {
724
725                    var comparator = this.comparators[i];
726
727                    if ( comparator.can(source) ) {
728       
729                            // once we've identified which DeepCopier to use, we need to call it in a very
730                            // particular order: create, cache, populate.  This is the key to detecting cycles.
731                            // We also keep track of recursion depth when calling the potentially recursive
732                            // populate(): this is a fail-fast to prevent an infinite loop from consuming all
733                            // available memory and crashing or slowing down the browser.
734     
735                            if( !result )
736                                // Start by creating a stub object that represents the copy.
737                                result = comparator.create(source);
738                            else if( !comparator.can(result) )
739                                throw new Error("can't compare diferent kind of objects.");
740
741                            // we now know the deep copy of source should always be result, so if we encounter
742                            // source again during this deep copy we can immediately use result instead of
743                            // descending into it recursively. 
744                            depth.cacheResult(source, result);
745
746                            // only DeepCopier.populate() can recursively deep copy.  So, to keep track
747                            // of recursion depth, we increment this shared counter before calling it,
748                            // and decrement it afterwards.
749                            depth.depth++;
750                            if ( depth.depth > depth.maxDepth ) {
751                                    throw new Error("Exceeded max recursion depth in deep copy.");
752                            }
753
754                            var thisPass = this;
755
756                            // It's now safe to let the comparator recursively deep copy its properties.
757                            comparator.populate( function(source, result) { return thisPass.copy(source, result, depth); }, source, result );
758
759                            depth.depth--;
760
761                            return result;
762                    }
763            }
764            // the generic copier can handle anything, so we should never reach this line.
765            throw new Error("no DeepCopier is able to copy " + source);
766    },
767
768    // publicly expose the list of deepCopiers.
769    comparators: [],
770
771    // make deep copy() extensible by allowing others to
772    // register their own custom Comparators.
773    registerComparator: function(comparatorOptions) {
774
775          // publicly expose the Comparator class.
776          var comparator = {
777
778              // determines if this Comparator can handle the given object.
779              can: function(source) { return false; },
780   
781              // starts the deep copying process by creating the copy object.  You
782              // can initialize any properties you want, but you can't call recursively
783              // into the copy().
784              create: function(source) { },
785
786              // Completes the deep copy of the source object by populating any properties
787              // that need to be recursively deep copied.  You can do this by using the
788              // provided deepCopyAlgorithm instance's copy() method.  This will handle
789              // cyclic references for objects already deepCopied, including the source object
790              // itself.  The "result" passed in is the object returned from create().
791              populate: function(deepCopyAlgorithm, source, result) {}
792          };
793
794          for ( var key in comparatorOptions ) comparator[key] = comparatorOptions[key];
795
796          this.comparators.unshift( comparator );
797    },
798 
799    diff: function( base, toDiff ){
800
801        if( typeof base === 'undefined' || $.isEmptyObject(base) )
802            return( toDiff );
803
804        if( toDiff === false )
805            return( false );
806
807        toDiff = $.extend( {}, toDiff );
808
809        for( var key in toDiff )
810        {
811            switch( $.type(toDiff[key]) )
812            {
813              case 'object':
814                if( $.isEmptyObject(toDiff[key] = this.diff( base[key], toDiff[key] )) )
815                  delete toDiff[key];
816              break;
817              case 'array':
818                if( base[key] && !(toDiff[key] = $.grep( toDiff[key], function( el, i ){ return( $.inArray( el, base[key] ) === -1 ); } )).length )
819                  delete toDiff[key];
820              break;
821              default:
822                if( base[key] == toDiff[key] )
823                  delete toDiff[key];
824            }
825        }
826
827        return( toDiff );
828
829    },
830   
831    links: function( concept, reverse ){
832
833        if( !this.links[ concept ] )
834        {
835            var result = this.dispatch( "links", { concept: concept } ) || false;
836
837            if( !result )
838                return( false );
839
840            this.concepts[ concept ] = $.extend( this.concepts[ concept ] || {},
841                                                 result['concepts'] || {} );
842
843            this.links[ concept ] =  result['links'] || {};
844        }
845
846        if( reverse )
847        {
848            var reverted = {}, llinks = this.links[ concept ];
849   
850            for( var key in llinks )
851                reverted[ llinks[key] ] = key;
852
853            return( reverted );
854        }
855
856        return( this.links[ concept ] );
857
858    },
859   
860    isConcept: function( concept, attr ){
861     
862        if( typeof this.concepts[concept] === "undefined" )
863        {
864            this.links( concept );
865        }
866
867        return !!this.concepts[ concept ][ attr ];
868    },
869   
870    URI: function( concept, URI, context ){
871     
872        if( res = internalUrl.exec( concept ) )
873            concept = res[1];
874       
875        context = context ? "(" + context + ")" : "";
876     
877        if( URI )
878            return( concept + context + "://" + URI );
879        else
880            return( concept );
881     
882    },
883   
884    parseURI: function( URI ){
885
886        return internalUri.exec( URI ) || false;
887
888    },
889   
890   
891   
892   
893    generateId: function( concept ){
894     
895        var newId = this.counter + "(javascript)";
896     
897        this.store( ":counter", (this.counter++) + "" );
898       
899        return( newId );
900    },
901   
902
903   
904
905    get: function( concept, /*URI, */filter, oneSide ){
906
907        ///////////////////////////// normalize ////////////////////////////////
908        if( arguments.length == 2 && $.type(filter) === "boolean" )
909        {
910            oneSide = filter;
911            filter = false;
912        }
913       
914        var encoder = false, id = false, bothSides = (typeof oneSide === 'undefined'), res;
915       
916        if( $.type(filter) === "string" )
917        {
918            id = filter;
919            filter = false;
920        }
921
922        filter = filter || false;
923
924        if( !concept )
925            return( false );
926
927        if( res = internalUrl.exec( concept ) )
928        {
929            encoder = concept;
930            concept = res[1];
931
932            if( filter )
933                filter = this.criteria( encoder, filter );
934        }
935       
936        if ( $.type(filter) === "array" )
937        {
938            filter = { filter: filter, criteria: false };
939        }
940       
941        //////////////////////////////////////////////////////////////////////////
942       
943        var result = false;
944
945        if( bothSides || !oneSide )
946            result = this.check( concept, id || filter );
947
948        if( !result && (bothSides || oneSide) )
949        {
950            result = this.request( concept, id || filter.filter, filter.criteria );
951
952            if( result && bothSides && !filter.criteria.format )
953            {
954              var newResult = [];
955           
956              for( var i = 0; i < result.length; i++ )
957                  newResult[i] = $.extend( {}, result[i] );
958
959              this.put( concept, id, newResult, false );
960            }
961        }
962
963        if( /*result &&*/ encoder )
964            result = this.encode( encoder, result, filter ); //TODO: retirar o filtro no método encode
965
966        return( result );
967    },
968   
969   
970    filter: function( base, filter ){
971     
972        var filtered = [];
973     
974//      var operator = filter.shift();
975     
976        /*for( var key in base )
977        {
978            switch( operator )
979            {
980                case 'AND':
981                  for( var i = 0, current = true; i < filter.length && current; i++ )
982                    current = this.compare( '&', current, this.compare( base[key], filter[i] ) );
983                break;
984                case 'OR':
985                  for( var i = 0, current = false; i < filter.length && !current; i++ )
986                    current = this.compare( '|', current, this.compare( base[key], filter[i] ) );
987                break;
988                case 'IN':
989                  for( var i = 0, current = false; i < filter[1].length && !current; i++ )
990                    current = this.compare( '|', current, this.compare( base[key], [ '=', filter[0], filter[1][i] ] ) );
991                break;
992                default : current = this.compare( operator, base[key], );
993            }
994        */   
995//          if( !noGroup )
996//              for( var i = 0, current = original; i < filter.length && ( current === original ); i++ )
997//                  current = this.compare( operator, current, this.compare( base[key], filter[i] ) );
998
999//          if( current )
1000//              filtered[ filtered.length ] = key;
1001//      }
1002
1003        return( filtered );
1004    },
1005   
1006    compare: function( operator, base, test ){
1007     
1008      switch( operator )
1009      {
1010          case '*':  return  RegExp( "*" + base + "*" ).test( test );
1011          case '^':  return  RegExp( "^" + base +  "" ).test( test );
1012          case '$':  return  RegExp( ""  + base + "$" ).test( test );
1013
1014          case '&': return ( base && test );
1015          case '|': return ( base || test );
1016
1017          case '=':  return ( base == test );
1018          case '<=': return ( base <= test );
1019          case '>=': return ( base >= test );
1020          case '>':  return ( base <  test );
1021          case '<':  return ( base >  test );
1022      }
1023     
1024    },
1025   
1026//     clone: function( object ){
1027//
1028//      new { prototype: object };
1029//
1030//     },
1031
1032    check: function( namespace, keys ){
1033
1034        if( !namespace )
1035            return( false );
1036
1037        var result = this.storage.get( namespace );
1038
1039        if( !keys || !result )
1040          return( result || false );
1041
1042        if( notArray = $.type(keys) === "string" )
1043            keys = [ keys ];
1044        else if( $.type(keys) !== "array" )
1045            keys = this.filter( result, keys.filter );
1046
1047        var res = [];
1048
1049        for( var i = 0; i < keys.length; i++ )
1050            res[ res.length ] = result[keys[i]];
1051
1052        return( notArray ? res[0] || false : res.length ? res : false );
1053    },
1054
1055    storage: {
1056     
1057        cache: {},
1058     
1059        set: function( key, value ){
1060
1061            this.cache[key] = value;
1062
1063        },
1064        get: function( key ){
1065
1066            return DataLayer.copy( this.cache[key] );
1067
1068        },
1069        del: function( key ){
1070
1071            delete this.cache[key];
1072
1073        }
1074    },
1075
1076    flush: function(){
1077
1078    },
1079   
1080    restore: function(){
1081     
1082    },
1083
1084    store: function( namespace, key, data ){
1085
1086        if( !data )
1087          return this.storage.set( namespace, key );
1088
1089        var res = this.check( namespace ) || {};
1090
1091        res[key] = data;
1092
1093        return this.storage.set( namespace, res );
1094    },
1095
1096    del: function( namespace, key ){
1097     
1098        if( !key )
1099          return this.storage.del( namespace );
1100
1101        var res = this.check( namespace ) || {};
1102
1103        delete res[key];
1104
1105        return this.storage.set( namespace, res );
1106     
1107    },
1108   
1109     move: function( concept, oldId, newId ){
1110
1111        this.put( concept, newId, this.check( concept, oldId ), false );
1112
1113        this.del( concept, oldId );
1114    },
1115   
1116
1117   
1118   
1119   
1120    request: function( concept, filter, criteria ){
1121
1122      var id = false, criteria = criteria || {};
1123
1124      if( $.type(filter) === "string" )
1125      {
1126          id = filter;
1127          filter = false;
1128      }
1129
1130      return this.dispatch( "request", {
1131
1132          concept: concept || '',
1133          id: id || '',
1134          filter: filter || '',
1135          criteria: criteria || '',
1136          service: criteria.service || '',
1137          properties: criteria.properties || ''
1138
1139      } );
1140    },
1141
1142   
1143    //         sync: function( data, callback ){
1144//
1145//      if( !data || $.isEmptyObject( data ) )
1146//          return;
1147//       
1148//      this.send( "Sync", data, function( data, status, jqXHR ){
1149//
1150// //       switch( status )
1151// //       {
1152// //         case "error":
1153// //         case "parsererror":
1154// //           return DataLayer.rollback( concept, URI );
1155// //         case "success":
1156// //           return DataLayer.commit();
1157// //         case "timeout":
1158// //         case "notmodified":
1159// //       }
1160//
1161//          if( callback )
1162//          {
1163//              var result = callback( data, status, jqXHR );
1164//
1165//              if( result === false )
1166//                  return;
1167//              else if( typeof result != "undefined" )
1168//                  data = result;
1169//          }
1170//
1171//          for( var URI in data )
1172//          {
1173//              var parsed = DataLayer.parseURI( URI ),
1174//   
1175//              concept = parsed[1], /*URI = parsed[3],*/
1176//
1177//              links = DataLayer.links( concept );
1178//
1179//              for( var linkName in links )
1180//              {
1181//                  var subURI = data[URI][linkName];
1182//
1183//                  if( subURI && data[subURI] )
1184//                  {
1185//                      data[URI][linkName] = DataLayer.put( linkName, subURI, data[subURI], false );
1186//
1187//                      delete( data[subURI] );
1188//                  }
1189//              }
1190//
1191//              DataLayer.put( concept, URI, data[URI], false );
1192//          }
1193//      }, true );
1194//
1195//     },
1196
1197//     report: function( concept, URI, data, sync )
1198//     {
1199//      var current = this.dequeue( 'current', concept, URI );
1200//
1201//      if( !current )
1202//          this.enqueue( 'current', concept, URI, ( current = this.check( concept, URI ) || {} ) );
1203//
1204//      var diff = this.diff( current, data );
1205//
1206//      if( !diff )
1207//          this.dequeue( 'current', concept, URI, true );
1208//      else
1209//          this.enqueue( 'diff', concept, URI, diff );
1210//     
1211//      if( sync )
1212//          this.commit( concept, URI, function(){
1213//
1214//              DataLayer.set( concept, URI, data, false );
1215//
1216//          });
1217//     },
1218   
1219//     enqueue: function( type, concept, URI, obj ){
1220//       
1221//      //var newURI = this.URI( concept, URI );
1222//     
1223//      if( !this.queue[type] )
1224//          this.queue[type] = {};
1225//
1226//      if( !this.queue['all'] )
1227//          this.queue['all'] = {};
1228//     
1229//      if( !this.queue[type][concept] )
1230//          this.queue[type][concept] = {};
1231//     
1232//      if( !this.queue['all'][type] )
1233//          this.queue['all'][type] = {};
1234//     
1235//      if( !this.queue['all'][type][/*new*/URI] )
1236//          this.queue[type][concept][URI] = this.queue['all'][type][/*new*/URI] = obj;
1237//
1238//      this.store( ':queue', this.queue );
1239//     },
1240//     
1241//     dequeue: function( type, concept, URI, remove ){
1242//       
1243//       ///////////////////////////// normalize ////////////////////////////////
1244//      if( arguments.length < 4 && $.type(URI) === 'boolean' )
1245//      {
1246//          remove = URI;
1247//          URI = false;
1248//      }
1249//      if( arguments.length < 3 && $.type(concept) === 'boolean' )
1250//      {
1251//          remove = concept;
1252//          concept = false;
1253//      }
1254//       //////////////////////////////////////////////////////////////////////////
1255//       
1256//      if( !this.queue[type] || !this.queue['all'] )
1257//          return( false );
1258//     
1259//      if( !concept )
1260//      {
1261//          var obj = this.queue['all'][type];
1262//         
1263//          if( remove )
1264//          {
1265//              delete this.queue['all'][type];
1266//              delete this.queue[type];
1267//          }
1268//
1269//          this.store( ':queue', this.queue );
1270//          return( obj );
1271//      }
1272//
1273//      if( !this.queue[type][concept] )
1274//          return( false );
1275//     
1276//      if( !URI )
1277//      {
1278//          var obj = this.queue[type][concept];
1279//
1280//          if( remove )
1281//          {
1282//              var URIs = this.queue[type][concept];
1283//
1284//              for( var subURI in URIs )
1285//                   delete this.queue['all'][type][subURI];
1286//
1287//              delete this.queue[type][concept];
1288//          }
1289//
1290//          this.store( ':queue', this.queue );
1291//          return( obj );
1292//      }
1293//
1294// //   var newURI = URI ? this.URI( concept, URI ) : concept;
1295//     
1296//      var obj = this.queue['all'][type][/*new*/URI];
1297//   
1298//      if( remove )
1299//      {
1300//          delete this.queue['all'][type][/*new*/URI];
1301//          delete this.queue[type][concept][URI];
1302//      }
1303//
1304//      this.store( ':queue', this.queue );
1305//      return( obj );
1306//     },
1307   
1308           //TODO: definir a 'usage' desta função e refatora-la
1309//     set: function( concept, filter, data, oneSide ){
1310//
1311//      ///////////////////////////// normalize ////////////////////////////////
1312//      if( arguments.length == 2 )
1313//      {
1314//          data = filter;
1315//          filter = false;
1316//      }
1317//      if( $.type(data) === "boolean" )
1318//      {
1319//          oneSide = data;
1320//          data = filter;
1321//          filter = false;
1322//      }
1323//     
1324//      if( !concept || !data )
1325//          return( false );
1326//
1327//      var decoder = "", URI = false, bothSides = (typeof oneSide === "undefined");
1328//     
1329//      if( $.type(filter) === "string" )
1330//      {
1331//          URI = filter;
1332//          filter = false;
1333//      }
1334//
1335//      if( res = internalUrl.exec( concept ) )
1336//      {
1337//          //TODO: verificar se a decodificaçao deve ser feita em cada item do array
1338//          data = this.decode( concept, data );
1339//          concept = res[1];
1340//          decoder = res[2];
1341//      }
1342//      ///////////////////////////////////////////////////////////////////////////
1343//
1344//      if( bothSides || oneSide )
1345//          this.report( concept, URI, data, !bothSides );
1346//
1347//      if( bothSides || !oneSide )
1348//      {
1349//          if( URI )
1350//          {
1351//            var helper = {};
1352//            helper[URI] = data;
1353//            data = helper;
1354//          }
1355//
1356//          for( var URI in data )
1357//          {
1358//              var current = this.check( concept, URI ) || {};
1359//
1360//              data[URI] = this.merge( current, data[URI] );
1361//
1362//              this.store( concept, URI, data[URI] );
1363//          }
1364//
1365//      }
1366//
1367//      this.broadcast( concept, oneSide ? 'client' : 'server' );
1368//
1369//      return( true );
1370//     },
1371//     put: function( concept, URI, data, oneSide ){
1372//       
1373//       ///////////////////////////// normalize ////////////////////////////////
1374//      if( $.type(URI) !== "string" && arguments.length < 4 )
1375//      {
1376//          oneSide = data;
1377//          data = URI;
1378//          URI = false;
1379//      }
1380//       ////////////////////////////////////////////////////////////////////////
1381//       
1382//       ////////////////////////////// linkage /////////////////////////////////
1383//      var result = false, links = this.links( concept );
1384//
1385//      for( var link in links )
1386//      {
1387//          if( data[link] )
1388//          {
1389//              if( $.isArray( data[link] ) )
1390//              {
1391//                  data[link] = this.put( links[link], data[link].URI, data[link], oneSide );
1392//              }
1393//              else if( $.isObject( data[link] ) )
1394//              {
1395//                  $.each( data[link], function( i, el ){
1396//
1397//                        data[link][i] = this.put( links[link], el.URI, el, oneSide );
1398//
1399//                  });
1400//              }
1401//          }
1402//      }
1403//       //////////////////////////////////////////////////////////////////////////
1404//     
1405//      if( typeof data.URI === "undefined" )
1406//      {
1407//          URI = this.add( concept, data, oneSide );
1408//      }
1409//      else if( data.URI === false )
1410//      {
1411//          status = this.remove( concept, URI, oneSide );
1412//      }
1413//      else
1414//      {
1415//          status = this.set( concept, URI, data, oneSide );
1416//      }
1417//
1418//      if( URI && data.URI && URI !== data.URI )
1419//          this.move( concept, URI, data.URI );
1420//
1421//      return( data.URI || URI );
1422//
1423//     },
1424   
1425    //     add: function( concept, data, oneSide ){
1426//       
1427//       ///////////////////////////// normalize ////////////////////////////////
1428//      if( !concept || !data )
1429//          return( false );
1430//
1431//      if( res = internalUrl.exec( concept ) )
1432//      {
1433//          //TODO: verificar se a decodificaᅵᅵo deve ser feita em cada item do array
1434//          data = this.decode( concept, data );
1435//          concept = res[1];
1436//          decoder = res[2];
1437//      }
1438//
1439//      var bothSides = (typeof oneSide === "undefined"), uris = [];
1440//
1441//      if( notArray = $.type(data) !== "array" )
1442//          data = [ data ];
1443//       //////////////////////////////////////////////////////////////////////////
1444//
1445//      for( var i = 0; i < data.length; i++ )
1446//      {
1447//          var URI = uris[i] = this.generateURI( concept );
1448//
1449//          this.set( concept, URI, data[i], oneSide );
1450//      }
1451//
1452//      return( notArray ? uris[0] : uris );
1453//     },
1454//      put: function( concept, data ){
1455//
1456//      var decoder = "";
1457//
1458//      if( res = internalUrl.exec( concept ) )
1459//      {
1460//          data = this.decode( concept, data );
1461//          concept = res[1];
1462//          decoder = res[2];
1463//      }
1464//
1465//      var New = [], Update = [], uris = [];
1466//
1467//      if( notArray = $.type(data) !== "array" )
1468//          data = [ data ];
1469//     
1470//      for( var i = 0; i < data.length; i++ )
1471//      {
1472//          if( !data[i].URI )
1473//          {
1474//              uris[ uris.length ] = data[i].URI = this.create( concept, data[i] );
1475//              New[ New.length ] = data[i];
1476//              continue;
1477//          }
1478//
1479//          for( var key in data[i] )
1480//              if( klass = this.isReference( concept, key, data[i][key] ) )
1481//                    data[i][key] = this.put( klass + decoder, data[i][key] );
1482//
1483//          Update[ Update.length ] = this.update( concept, data[i].URI, data[i] );
1484//      }
1485//
1486//      this.report( concept, { "created": New, "updated": Update });
1487//
1488//      return( notArray ? uris[0] : uris );
1489//     },
1490//     merge: function( concept, current, data ){
1491//
1492//      current = current || {};
1493//
1494//      for( var key in data )
1495//          current[key] = (klass = this.isReference( concept, key, data[key] )) ?
1496//                         this.merge( klass, current[key], data[key] ) : data[key];
1497//
1498//      return( current );
1499//     },
1500//
1501//     isReference: function( concept, key, value ){
1502//
1503//       return( ($.type(value) === "object" ||
1504//             $.type(value) === "array" )? this.links[concept][key] : false );
1505//
1506//     },
1507//     
1508//     set: function( concept, data, URI, mergeable ){
1509//     
1510//      if( URI )
1511//      {
1512//          var res = this.get( concept, true ) || {};
1513//         
1514//          if( mergeable )
1515//              data = this.merge( res[URI] || {}, data );
1516//
1517//          res[URI] = data;
1518//
1519//          data = res;
1520//      }
1521//
1522//      return this.store( concept, data );
1523//     },   
1524//
1525//     create: function( concept, data ){
1526//
1527//       if( notArray = ($.type(data) !== "array") )
1528//          data = [ data ];
1529//
1530//       var uris = [];
1531//
1532//       for( var i = 0; i < data.length; i++ )
1533//       {
1534//        uris[ uris.length ] = data[i].URI = "javascript://" + (this.counter + i);
1535//
1536//        this.set( concept, data[i], data[i].URI );
1537//       }
1538// 
1539//       this.set( ":counter", (this.counter += data.length) );
1540//
1541//       return notArray ? uris[0] : uris;
1542//     },
1543//
1544//     update: function( concept, URI, data )
1545//     {
1546//      var target = this.check( concept, URI ) || {};
1547//
1548//      target = this.merge( concept, target, data );
1549//
1550//      if( target.URI !== URI )
1551//          this.remove( concept, URI );
1552//
1553//      this.set( concept, target, target.URI );
1554//
1555//      return( target );
1556//     },
1557//
1558//     remove: function( concept, URI ){
1559//
1560//      if( !URI )
1561//          return this.storage.del( concept );
1562//
1563//      var res = this.check( concept );
1564//
1565//      delete res[URI];
1566//     
1567//      this.set( concept, res );
1568//     },
1569//
1570//     del: function( concept, URI ){
1571//
1572//      this.remove( concept, URI );
1573//
1574//      this.report( concept, { "deleted": { 'URI': URI } });
1575//     },
1576//
1577//     report: function( concept, changes ){
1578//
1579//       this.broadcast( concept, changes.created, changes.updated, changes.deleted );
1580//
1581//      if( changes.created )
1582//          this.sync( concept, changes.created, 'create' );
1583//      if( changes.updated )
1584//          this.sync( concept, changes.updated, 'update' );
1585//      if( changes.deleted )
1586//          this.sync( concept, changes.deleted, 'delete' );
1587//
1588//     },
1589//
1590//
1591//    sync: function( concept, data, type ){
1592//
1593//      if( $.type(data) !== "array" )
1594//          data = [ data ];
1595//
1596//      $.each( data, function( i, el ){
1597//
1598//         DataLayer.send( concept, el, type );
1599//
1600//      });
1601//
1602//     },
1603//     
1604//     
1605//     
1606//     
1607//
1608//     request: function( concept, URI, filter ){
1609//
1610// //       if( startsDoubleDot.test(concept) )
1611// //     return( false );
1612//
1613//       filter = filter || {};
1614//
1615//       if( URI )
1616//      filter.URI = URI;
1617//
1618//       return this.send( concept, filter, "read", true );
1619//
1620//     },
1621//
1622//     send: function( concept, data, type, wait ){
1623//
1624//       switch( type )
1625//       {
1626//      case "create": type = "POST"; break;
1627//      case "update": type = "PUT"; break;
1628//      case "delete": type = "DELETE"; break;
1629//      case "read": type = "GET"; break;
1630//       }
1631//
1632//       var url = this.basePath + concept;
1633//
1634//       var result = [], notArray = false;
1635//
1636// //      alert( data.URI );
1637//
1638//       if( data.URI && data.URI.indexOf("javascript://") !== 0 )
1639//        url += "/" + data.URI;
1640//
1641//       var callback = function( dt, textStatus, jqXHR ){
1642//
1643//          if( notArray = (!$.isArray( dt )) )
1644//              dt = [ dt ];
1645//
1646//          $.each( dt, function( i, el ){
1647//
1648//              if( !el || !el.URI )
1649//                  return;
1650//
1651//              if( data.URI )
1652//                  el = DataLayer.update( concept, data.URI, el );
1653//              else
1654//                  DataLayer.set( concept, el, el.URI );
1655//
1656//              result[ result.length ] = el;
1657//              DataLayer.broadcast( concept );
1658//        });
1659//       };
1660//
1661//       $.ajax({
1662//            'async': ( !wait ),
1663//            'url': url,
1664//            'type': type,
1665//            'success': callback,
1666//            'dataType': 'json',
1667//            'data': data/*,
1668//            'processData': false*/
1669//        });
1670//
1671//       return( notArray ? result[0] || false : result );
1672//     },
1673   
1674   
1675    generateURI: function( concept ){
1676     
1677        return this.URI( concept, this.generateId( concept ), "javascript" );
1678
1679    },
1680   
1681
1682    broadcast: function( concept, status, diff ){
1683
1684        if( this.listeners[ concept ] )
1685            for( var i = 0;
1686                i < this.listeners[ concept ].length;
1687                this.listeners[ concept ][ i++ ]( status, diff ) );
1688    },
1689
1690    listen: function( concept, listener ){
1691
1692        this.register( "listeners", concept, listener );
1693
1694    },
1695
1696    codec: function( concept, namespace, codec ){
1697
1698        if( codec.encoder )
1699            this.encoder( concept, namespace, codec.encoder );
1700        if( codec.decoder )
1701            this.decoder( concept, namespace, codec.decoder );
1702        if( codec.criteria )
1703            this.register( "criterias", concept + ":" + namespace, codec.criteria );
1704
1705    },
1706
1707    encoder: function( concept, namespace, encoder ){
1708
1709        this.register( "encoders", concept + ":" + namespace, encoder );
1710
1711    },
1712
1713    encode: function( encoder, data, filter ){
1714
1715        if( this.encoders[ encoder ] )
1716            for( var i = 0;
1717                i < this.encoders[ encoder ].length;
1718                data = this.encoders[ encoder ][ i++ ]( data, filter ) );
1719
1720        return( data );
1721    },
1722
1723    decoder: function( concept, namespace, decoder ){
1724
1725        this.register( "decoders", concept + ":" + namespace, decoder );
1726
1727    },
1728
1729    decode: function( decoder, data ){
1730
1731        if( this.decoders[ decoder ] )
1732            for( var i = 0;
1733                i < this.decoders[ decoder ].length;
1734                data = this.decoders[ decoder ][ i++ ]( data ) );
1735
1736        return( data );
1737    },
1738
1739    criteria: function( codec, filter ){
1740
1741        if( this.criterias[ codec ] )
1742            for( var i = 0;
1743                i < this.criterias[ codec ].length;
1744                filter = this.criterias[ codec ][ i++ ]( filter ) );
1745
1746        return( filter );
1747
1748    },
1749
1750    register: function( kind, concept, deployable ){
1751
1752      if( arguments.length < 3 )
1753      {
1754          deployable = concept;
1755          concept = kind;
1756          kind = 'global';
1757      }
1758
1759      if( !this[ kind ][ concept ] )
1760            this[ kind ][ concept ] = [];
1761
1762        this[ kind ][ concept ][ this[ kind ][ concept ].length ] = deployable;
1763
1764    },
1765   
1766    start: function(){
1767
1768        var timer = function(){
1769
1770              setTimeout( timer, 1 );
1771
1772              var now = parseInt( $.now() / 1000 );
1773
1774              var tasks = DataLayer.tasks[ now ];
1775
1776              if( !tasks ) return;
1777
1778              for( var i = 0; i < tasks.length; i++ )
1779              {
1780                  var result = tasks[i].task( now );
1781
1782                  if( tasks[i].factor )
1783                  DataLayer.schedule( tasks[i].task, tasks[i].factor );
1784              }
1785     
1786              delete DataLayer.tasks[ now ];
1787        };
1788
1789        setTimeout( timer, 1 );
1790    },
1791   
1792    task: function( timestamp, task, factor )
1793    {
1794        if( !this.tasks[ timestamp ] )
1795            this.tasks[ timestamp ] = [];
1796
1797        this.tasks[ timestamp ][ this.tasks[ timestamp ].length ] = { task: task, factor: factor || false };
1798    },
1799
1800    schedule: function( task, time ){
1801
1802        time = time || 1;
1803       
1804        var index = parseInt( $.now() / 1000 ) + time;
1805
1806        this.task( index, task, time );
1807    },
1808   
1809    poll: function( concept, time ){
1810     
1811      this.schedule( function( now ){
1812 
1813          DataLayer.commit( concept );
1814
1815        }, time || 5 );
1816    },
1817   
1818    init: function(){
1819     
1820        this.counter = parseInt( this.get( ":counter", false ) ) || 0;
1821
1822        if( !this.dispatchPath )
1823            this.dispatchPath = "../../";
1824
1825        if( !this.templatePath )
1826            this.templatePath = "";
1827
1828        if( !this.basePath )
1829            this.basePath = this.dispatchPath + "REST.php?q=";
1830
1831        this.schedule( function( now ){
1832
1833            DataLayer.flush();
1834
1835        });
1836
1837        this.start();
1838    }
1839}
1840
1841// the re-usable constructor function used by clone().
1842function Clone() {}
1843
1844//Recursion Helper
1845function RecursionHelper(){ this.clear(); };
1846
1847RecursionHelper.prototype = {
1848 
1849        constructor: RecursionHelper,
1850
1851        // copiedObjects keeps track of objects already copied by this
1852        // deepCopy operation, so we can correctly handle cyclic references.
1853        copiedObjects: [],
1854
1855        depth: 0,
1856
1857        maxDepth: 256,
1858
1859        //reset the recursion helper cache
1860        clear: function(){
1861                this.copiedObjects = [];
1862                this.depth = 0;
1863        },
1864
1865        // add an object to the cache.  No attempt is made to filter duplicates;
1866        // we always check getCachedResult() before calling it.
1867        cacheResult: function(source, result) {
1868                this.copiedObjects.push([source, result]);
1869        },
1870
1871        // Returns the cached copy of a given object, or undefined if it's an
1872        // object we haven't seen before.
1873        getCachedResult: function(source) {
1874
1875                for ( var i=0; i<this.copiedObjects.length; i++ ) {
1876                        if ( this.copiedObjects[i][0] === source ) {
1877                                return this.copiedObjects[i][1];
1878                        }
1879                }
1880
1881                return undefined;
1882        }
1883};
1884
1885// Generic Object copier
1886// the ultimate fallback DeepCopier, which tries to handle the generic case.  This
1887// should work for base Objects and many user-defined classes.
1888DataLayer.registerComparator({
1889        can: function(source) { return true; },
1890
1891        create: function(source) {
1892                if ( source instanceof source.constructor ) {
1893                        return DataLayer.clone(source.constructor.prototype);
1894                } else {
1895                        return {};
1896                }
1897        },
1898
1899        populate: function(deepCopy, source, result) {
1900                for ( var key in source ) {
1901                        if ( source.hasOwnProperty(key) ) {
1902                                result[key] = deepCopy(source[key], result[key]);
1903                        }
1904                }
1905                return result;
1906        }
1907});
1908
1909// Array copier
1910DataLayer.registerComparator({
1911        can: function(source) {
1912                return ( source instanceof Array );
1913        },
1914
1915        create: function(source) {
1916                return new source.constructor();
1917        },
1918
1919        populate: function(deepCopy, source, result) {
1920                for ( var i=0; i<source.length; i++) {
1921                        result.push( deepCopy(source[i], result[i]) );
1922                }
1923                return result;
1924        }
1925});
1926
1927// Date copier
1928DataLayer.registerComparator({
1929        can: function(source) {
1930                return ( source instanceof Date );
1931        },
1932
1933        create: function(source) {
1934                return new Date(source);
1935        }
1936});
1937
1938// HTML DOM Node copier
1939DataLayer.registerComparator({
1940
1941        // function to detect Nodes.  In particular, we're looking
1942        // for the cloneNode method.  The global document is also defined to
1943        // be a Node, but is a special case in many ways.
1944        can: function(source) {
1945         
1946          if ( window.Node ) {
1947                  return source instanceof Node;
1948          } else {
1949                  // the document is a special Node and doesn't have many of
1950                  // the common properties so we use an identity check instead.
1951                  if ( source === document ) return true;
1952                  return (
1953                          typeof source.nodeType === 'number' &&
1954                          source.attributes &&
1955                          source.childNodes &&
1956                          source.cloneNode
1957                  );
1958          }
1959      },
1960
1961      create: function(source) {
1962              // there can only be one (document).
1963              if ( source === document ) return document;
1964
1965              // start with a shallow copy.  We'll handle the deep copy of
1966              // its children ourselves.
1967              return source.cloneNode(false);
1968      },
1969     
1970      diff: function(base, source){
1971       
1972      },
1973
1974      populate: function(deepCopy, source, result) {
1975              // we're not copying the global document, so don't have to populate it either.
1976              if ( source === document ) return document;
1977
1978              // if this Node has children, deep copy them one-by-one.
1979              if ( source.childNodes && source.childNodes.length ) {
1980                      for ( var i=0; i<source.childNodes.length; i++ ) {
1981                              var childCopy = deepCopy(source.childNodes[i], result.childNodes[i] || false );
1982                              result.appendChild(childCopy);
1983                      }
1984              }
1985      }
1986});
1987
1988DataLayer.init();
1989
1990// setTimeout(function(){
1991// 
1992//     
1993//
1994// }, 1000 );
1995
1996// var DataLayer = {
1997//
1998//     get: function( concept, filter ){
1999//
2000//      var data = this.storage.get( concept );
2001//
2002//      if( !filter )
2003//          return( data );
2004//
2005//      return this.filter( data, filter );
2006//     },
2007//     
2008//     filter:function( data, filter ){
2009//       
2010//      if( filter.charAt )
2011//          filter = { URI: filter };
2012//     
2013//      var filtered = [];
2014//
2015//      $.each(data, function(i, obj){
2016//       
2017//          for( var attr in filter )
2018//              if( filter[attr] !== obj[attr] )
2019//                  return( true );
2020//
2021//          filtered[i] = obj;
2022//      });
2023//
2024//      return( filtered );
2025//     },
2026//
2027//     find: function( concept, filter, callback ){
2028//
2029//      var data = this.get( concept, filter );
2030//
2031//      if( data )
2032//          return callback( data );
2033//
2034//      //TODO: register callback like a weak listener
2035//
2036// //   $.ajax({
2037// //         type: 'GET',
2038// //         data: $.param( filter ),
2039// //         success: callback, 
2040// //         url: BASE_PATH + filter.URI || concept
2041// //   });
2042//      this.report( concept, filter );
2043//     },
2044//
2045//     put: function( concept, data, filter ){
2046//
2047//      var beforeDiff = this.store( concept, $.extend({},data) );
2048//
2049//      this.report( concept, data, filter, beforeDiff );
2050//     },
2051//     
2052//     
2053//     /*var data = {
2054//                      startTime: $.now(),
2055//                      endTime: $.now() + 1800000,
2056//                      summary: "meu querido evento",
2057//                      description: "desc do evento",
2058//                      location: "prognus software livre",
2059//                      class: 1,
2060//                      calendar: 1,
2061//                      category: 1,
2062//                      participants: [ {
2063//                                         user: { isExternal: true, mail: "user7@prognus.org", name: "user7" }
2064//                                    },{
2065//                                         user: "1003"
2066//                                    } ]
2067//
2068//                };*/
2069//     
2070//
2071//     merge:function( data, target ){
2072//       
2073//      var diff = { New: {}, Update:{}, Delete: {} };
2074//       
2075//      for( var key in data )
2076//      {
2077//          if( !target[ key ] )
2078//              diff.New[ key ] = target[ key ] = data[ key ];
2079//
2080//         
2081//       
2082//      }
2083//       
2084//     }
2085//
2086//     store: function( concept, data, filter ){
2087//
2088//      if( !data.spline )
2089//          data = [ data ];
2090//
2091//      var target = this.storage.get( concept );
2092//     
2093//      var diff = { New: {}, Update:{}, Delete: {} };
2094//
2095//      for( var i = 0; i < data.length; i++ )
2096//      {
2097//          if( data[i].URI && target[ data[i].URI ] )
2098//          {
2099//              diff.Update[ data[i].URI ] = this.merge( target[ data[i].URI ], data[i] );
2100//          }
2101//          else
2102//          {
2103//              diff.New[] = data[i];
2104//          }
2105//      }
2106//
2107//     
2108//
2109//      this.broadcast( concept, data );
2110//
2111//      if( filter )
2112//          target = this.filter( target, filter );
2113//
2114//      if( target )
2115//          data = $.extend( target, data );
2116//
2117//      this.storage.set( concept, data );
2118//
2119// //   return;
2120//     },
2121//     
2122//     set: function( concept, data, filter ){
2123//
2124//       
2125//
2126//     },
2127//
2128//     post: function( concept, data, filter, isNew ){
2129//
2130//      var callback = function(  ){ DataLayer.store( concept, data, filter ) };
2131//
2132//      //TODO: register callback like a weak listener
2133//
2134//      this.report( concept, data, filter, isNew );
2135//     },
2136//     
2137//     report: function( concept, filter, postData, isNew ){
2138//       
2139//      $.ajax({
2140//              type: postData ? isNew ? 'POST' : 'PUT' : 'GET',
2141//              data: postData || $.param( filter ),
2142//              success: function( data ){ DataLayer.broadcast( concept ) },
2143//              url: BASE_PATH + filter.URI || concept
2144//        });
2145//     },
2146//     
2147//     del:function( concept, filter ){
2148//
2149//       
2150//
2151//     }
2152//     
2153//     broadcast: function( concept, data ){
2154//
2155//     
2156//
2157//     },
2158//
2159//     pool: function(){
2160//       
2161//     },
2162//
2163//     refresh: function(){
2164//       
2165//     }
2166// };
2167
2168//
2169// DataLayer = {
2170//   
2171//     get: function( concept, filter ){
2172//
2173//      var data = this.storage.get( concept );
2174//
2175//      if( !filter )
2176//          return( data );
2177//
2178//      if( filter.charAt )
2179//          filter = { URI: filter };
2180//     
2181//      var filtered = [];
2182//
2183//      $.each(data, function(i, obj){
2184//       
2185//          for( var attr in filter )
2186//              if( filter[attr] !== obj[attr] )
2187//                  return( true );
2188//
2189//          filtered[i] = obj;
2190//      });
2191//
2192//      return( filtered );
2193//     },
2194//
2195//     find: function( concept, filter, callback ){
2196//
2197//      var data = this.get( concept, filter );
2198//
2199//      if( data )
2200//          return callback( data );
2201//
2202//       $.ajax({
2203//            type: 'GET',
2204//            data: $.param( filter ),
2205//            success: callback, 
2206//            url: filter.URI || concept
2207//      });
2208//     },
2209//
2210//     put: function( concept, data, filter ){
2211//
2212//      var target = this.get( concept, filter );
2213//
2214//      if( target )
2215//          data = $.extend( target, data );
2216//       
2217//      this.storage.set( concept, data );
2218//     
2219//      //diff
2220//     },
2221//     
2222//     post: function( concept, data, filter ){
2223//
2224//     
2225//
2226//     },
2227//     
2228//     pool: function(){
2229//       
2230//     },
2231//     
2232//     queue: function(){
2233//       
2234//     },
2235//     
2236//     dequeue: function(){
2237//       
2238//     },
2239//     
2240//     refresh: function(){
2241//       
2242//     }
2243// }
2244
2245// var DataLayer = {
2246 
2247//       cache: {},
2248 
2249//       get: function( concept, location ){
2250       
2251           /* if( location )
2252            {*/
2253//              var schema = $.data( this.cache, concept + ':schema' );
2254//              var uri = [];
2255//
2256//              $.each( schema, function( i, addrs ){
2257//                    uri[ uri.length ] = location[addrs];
2258//              });
2259
2260                /*var filter = [], result = false;
2261
2262                while( !(result = $.data( this.cache, uri.join( '.' ) )) || !(uri = uri.join('.')) )
2263                  filter[ filter.length ] = uri.pop();
2264 
2265                if( !filter.length )
2266                {
2267                    var indexes = $.data( this.cache, uri + ':indexes' );
2268
2269                    if( indexes )
2270                        Array.prototype.concat.apply( result, indexes );
2271                   
2272                    return( result );
2273                }
2274
2275                for( var i = 0; i < result.length; i++ )
2276                {
2277                   
2278                }
2279
2280                if( result.length )
2281                    return( result );
2282            }*/
2283
2284//          var data = $.data( this.cache, concept );
2285
2286//          if( !data )
2287//              $.ajax( );
2288
2289//          return( data );
2290//       },
2291     
2292//       data: function(){
2293//
2294//       
2295//
2296//       }
2297//       
2298//       search: function( concept, filter ){
2299//
2300//        var schema = $.data( this.cache, concept + ':schema' );
2301//        var uri = [];
2302//
2303//        $.each( schema, function( i, addrs ){
2304//              uri[ uri.length ] = location[addrs];
2305//        });
2306//       }
2307//       put: function( concept, data, location ){
2308
2309//          if( location )
2310//          {
2311//              var schema = $.data( this.cache, concept + ':schema');
2312//              var uri = [];
2313
2314//              $.each( schema, function( i, addrs ){
2315//                    uri[ uri.length ] = location[addrs];
2316//              });
2317
2318//              var result = false, filter = [];
2319
2320//              while( !(result = $.data( this.cache, uri.join('.')) )
2321//                  filter[ filter.length ] = uri.pop();
2322
2323//              $.data( this.cache, '
2324
2325//          }
2326
2327//              var model = this.storage.get( concept );
2328//
2329//              $.each( model, function( i, o ){
2330//                  $.each( location, function( ii, attr ){
2331//                       if( o[ii] === attr )
2332//                          return( false );
2333//                  });
2334//              });
2335
2336//          return $.data( this.cache, concept, data );
2337
2338//       },
2339//       del: function( concept, location ){
2340//
2341//          if( location )
2342//          {
2343//              var schema = $.data( this.cache, 'concepts', concept );
2344//              var uri = [];
2345//
2346//              $.each( schema, function( i, addrs ){
2347//                    uri[ uri.length ] = location[addrs];
2348//              });
2349//
2350//              concept = uri.join( '.' );
2351
2352//              var model = this.storage.get( concept );
2353//
2354//              $.each( model, function( i, o ){
2355//                  $.each( location, function( ii, attr ){
2356//                       if( o[ii] === attr )
2357//                          return( false );
2358//                  });
2359//              });
2360//          }
2361//         
2362//     
2363//          $.removeData( this.cache, concept );
2364//       }
2365// }
Note: See TracBrowser for help on using the repository browser.