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

Revision 6008, 124.2 KB checked in by natan, 12 years ago (diff)

Ticket #2648 - Problema de sincronizacao de dados nos filtros de mensagens - Correcao no diff

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