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

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

Ticket #2434 - Implementacao de compartilhamento de agendas (agendas usuario e agendas publicas)

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