
  basis.require('basis.data');

 /**
  * @namespace basis.net.rpc
  */


  //
  // import names
  //

  var $undef = basis.fn.$undef;

  var STATE_READY = basis.data.STATE.READY;
  var STATE_PROCESSING = basis.data.STATE.PROCESSING;
  var STATE_ERROR = basis.data.STATE.ERROR;


  //
  // main part
  //

  // default callbacks
  var callback = {
    setProcessing: function(){
      this.setState(STATE_PROCESSING);
    },
    setReady: function(){
      this.setState(STATE_READY);
    },
    setError: function(error){
      this.setState(STATE_ERROR, error);
    },
    update_setReady: function(data){
      this.update(data);
      this.setState(STATE_READY);
    },
    commit_setReady: function(data){
      this.commit(data);
      this.setState(STATE_READY);
    },
    set_setReady: function(data){
      this.set(data || []);
      this.setState(STATE_READY);
    },
    sync_setReady: function(data){
      this.sync(data || []);
      this.setState(STATE_READY);
    }
  };

  // default transport handler
  var CALLBACK_HANDLER = {
    start: function(transport, request){
      this.start.call(request.requestData.origin);
    },
    success: function(transport, request, data){
      var origin = request.requestData.origin;

      this.success.call(origin, data);

      if (origin.state == STATE_PROCESSING)
        origin.setState(STATE_READY);
    },
    failure: function(transport, request, error){
      var origin = request.requestData.origin;

      this.failure.call(origin, error);

      if (origin.state == STATE_PROCESSING)
        origin.setState(STATE_ERROR, error);
    },
    complete: function(transport, request){
      this.complete.call(request.requestData.origin);
    }
  };

  // default callbacks
  var DEFAULT_CALLBACK = {
    start: callback.setProcessing,
    success: callback.setReady,
    failure: callback.setError,
    complete: $undef
  };

 /**
  * Creates a function that init service transport if necessary and make a request.
  * @function
  */
  function createRpc(config){
    // make a copy of config with defaults
    config = basis.object.extend({
      prepare: $undef,
      request: $undef
    }, config);

    // splice properties
    var fn = basis.object.splice(config, ['prepare', 'request']);
    var callback = basis.object.merge(
      DEFAULT_CALLBACK,
      basis.object.splice(config, ['start', 'success', 'failure', 'complete'])
    );

    // lazy transport
    var getTransport = basis.fn.lazyInit(function(){
      var transport = config.transport;

      if (!transport && config.service)
        transport = config.service.createTransport(config);

      if (!transport && config.createTransport)
        transport = config.createTransport(config);

      transport.addHandler(CALLBACK_HANDLER, callback);
      return transport;
    });

    return function rpc(){
      // this - instance of DataObject
      if (this.state != STATE_PROCESSING)
      {
        fn.prepare.apply(this, arguments);

        this.request = getTransport().request(basis.object.complete({
          origin: this
        }, fn.request.apply(this, arguments)));
      }
      else
      {
        ;;;basis.dev.warn(this + ' has not ready state. Operation aborted');
      }
    }
  }


 /**
  * @function
  */
  function createRpcFactory(service){
    return function rpcFactory(config){
      return createRpc(basis.object.complete({
        service: service
      }, config));
    }
  }


  //
  // export names
  //

  module.exports = {
    createRpc: createRpc,
    createRpcFactory: createRpcFactory,
    callback: callback
  };

@@ -106,35 +106,54 @@
 var 
-$undef = basis.fn.$undef
+STATE_UNDEFINED = basis.data.STATE.UNDEFINED
 ;%0A
-%0A
   va
@@ -318,16 +318,53 @@
 t%0A  //%0A%0A
+  var nothingToDo = function()%7B%7D;  %0A%0A
   // def
@@ -470,24 +470,99 @@
 NG);%0A    %7D,%0A
+    setUndefined: function()%7B%0A      this.setState(STATE_UNDEFINED);%0A    %7D,%0A
     setReady
@@ -1205,32 +1205,80 @@
 port, request)%7B%0A
+      var origin = request.requestData.origin;%0A%0A
       this.start
@@ -1307,24 +1307,112 @@
 ata.origin);
+%0A%0A      if (origin.state != STATE_PROCESSING)%0A        origin.setState(STATE_PROCESSING);
 %0A    %7D,%0A    
@@ -1864,24 +1864,238 @@
 or);%0A    %7D,%0A
+    abort: function(transport, request)%7B%0A      var origin = request.requestData.origin;%0A%0A      this.abort.call(origin);%0A%0A      if (origin.state == STATE_PROCESSING)%0A        origin.setState(STATE_UNDEFINED);%0A    %7D,%0A
     complete
@@ -2257,94 +2257,95 @@
 rt: 
-callback.setProcessing,%0A    success: callback.setReady,%0A    failure: callback.setError
+nothingToDo,%0A    success: nothingToDo,%0A    failure: nothingToDo,%0A    abort: nothingToDo
 ,%0A  
@@ -2356,22 +2356,27 @@
 mplete: 
-$undef
+nothingToDo
 %0A  %7D;%0A%0A 
@@ -2605,22 +2605,27 @@
 repare: 
-$undef
+nothingToDo
 ,%0A      
@@ -2637,14 +2637,19 @@
 st: 
-$undef
+nothingToDo
 %0A   
@@ -2881,16 +2881,25 @@
 ailure',
+ 'abort',
  'comple
@@ -3226,24 +3226,24 @@
 t(config);%0A%0A
-
       transp
@@ -3286,16 +3286,17 @@
 lback);%0A
+%0A
       re

handle transport abort event and turn origin into undefined state