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

Revision 5399, 58.1 KB checked in by cristiano, 12 years ago (diff)

Ticket #2434 - Alteração da estrutura de diretórios da nova API

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