Source: TwisterStream.js

var inherits = require('inherits');

var TwisterResource = require('./TwisterResource.js');
//var TwisterTorrent = require('./TwisterTorrent.js');

/**
 * Describes the stream of posts of a {@link TwisterUser}.
 * @class
 */
TwisterStream = function (name,scope) {
    
    TwisterResource.call(this,name,scope);
    
    this._latestId = -1;
    this._posts = {};
    this._verified = true; //post are verified individually
    
    this._activeTorrentUser = null;
    
    this._type = "stream";

}

inherits(TwisterStream,TwisterResource);

TwisterStream.prototype.flatten = function () {

    var flatData = TwisterResource.prototype.flatten.call(this);
    
    var flatPosts = [];
    
    for (var id in this._posts){
        flatPosts.push(this._posts[id].flatten());
    }
    
    flatData.posts = flatPosts;
    flatData.latestId  = this._latestId;
    flatData.activeTorrentUser  = this._activeTorrentUser;
    
    
    return flatData;


}

TwisterStream.prototype.inflate = function (flatData) {
    
  var Twister = this._scope;

  var TwisterPost = require('./TwisterPost.js');

  TwisterResource.prototype.inflate.call(this,flatData);

  this._latestId = flatData.latestId;
  this._activeTorrentUser = flatData.activeTorrentUser;
  
  for(var i in flatData.posts){

    if (flatData.posts[i].verified) {

      var newpost = new TwisterPost(flatData.posts[i].data,flatData.posts[i].signature,Twister);
      newpost.inflate(flatData.posts[i]);
      this._posts[newpost.getId()]=newpost;

    } else if (flatData.posts[i].data.k==this._latestId) {

      this._latestId = -1;
      this._lastUpdate = -1;

    }

  }

}

TwisterStream.prototype._do =  function (cbfunc) {
    
    this._doPost(this._latestId,cbfunc);
    
}

TwisterStream.prototype.updateCache = function (cbfunc) {
  
  var Twister = this._scope;
  
  if (this._activeTorrentUser) {
    Twister._wallet[this._activeTorrentUser]._torrents[this._name].updatePostsCache(cbfunc);
  } else {
    this._log("user has no active torrent")
    cbfunc(false);
  }

}

TwisterStream.prototype.fillCache = function (id,cbfunc) {
  
  var Twister = this._scope;
  
  if (this._activeTorrentUser) {
    Twister._wallet[this._activeTorrentUser]._torrents[this._name].fillPostsCache(id,cbfunc);
  } else {
    cbfunc(false);
  }

}

TwisterStream.prototype._queryAndDo = function (cbfunc) {
  
    var thisResource = this;
        
    thisResource.updateCache(function(success){

        if (success) {
            
            thisResource._log("updating cache with torrent successfull")
          
            thisResource._do(cbfunc);
            thisResource._updateInProgress = false;

        } else {
          
            thisResource._log("updating cache with torrent failed")

            thisResource.dhtget([thisResource._name, "status", "s"], function (result) {

                    thisResource._log("result from dhtget: "+JSON.stringify(result));
              
                    if (result[0]) {

                        thisResource._verifyAndCachePost(result[0].p.v, function(newpost) {

                            thisResource._latestId = newpost.getId();
                            thisResource._lastUpdate = Date.now()/1000;
                            thisResource._updateInProgress = false;

                            cbfunc(newpost);

                        });


                    } else { 
			
                      thisResource._handleError({
                        message: "DHT resource is empty.",
                        code: 32052
                      })
                      thisResource._updateInProgress = false;
                      //cbfunc(null);
                      
                    }

                }

            );

        }

    });  
        
}

TwisterStream.prototype._verifyAndCachePost =  function (payload,cbfunc) {
    
    var Twister = this._scope;
        
    var thisResource = this;
    
    var newid = payload.userpost.k;
    var payloadUser = payload.userpost.n;

    //console.log(payloadUser+":post"+newid);
    
    if( !( newid in thisResource._posts) ) {

		var signatureVerification = thisResource.getQuerySetting("signatureVerification");
		
        var TwisterPost = require('./TwisterPost.js');

        var newpost = new TwisterPost(payload.userpost,payload.sig_userpost,Twister);

        thisResource._posts[newpost.getId()] = newpost;
      
        if ( thisResource._latestId<newpost.getId() ) {
        
            thisResource._latestId=newpost.getId();
        
        }
        
        if (cbfunc && signatureVerification=="none") {
            
            thisResource._log("no signature verifcation needed");
          
            newpost._verified = true;
          
            cbfunc(newpost);
          

        } else {
        
			if (cbfunc && signatureVerification=="background") { 
              
              thisResource._log("issuing signature verification in background");
              
              cbfunc(newpost); 
            
            }
            
            var errorfunc = thisResource.getQuerySetting("errorfunc");
			
			Twister.getUser(thisResource._name)._doPubKey(function(pubkey){

				pubkey.verifySignature(payload.userpost,payload.sig_userpost,function(verified){

					if (verified) {

						newpost._verified=true;
                      
                        if (newpost.isRetwist()) {
                          
                          var post_rt = payload.userpost.rt;
                          var sig_rt = payload.userpost.sig_rt;
                          
                          Twister.getUser(post_rt.n)._doPubKey(function(pubkey){

                            pubkey.verifySignature(post_rt,sig_rt,function(verified){

                                if (verified) {
                                  
                                  if (cbfunc && signatureVerification=="instant") {
                                    cbfunc(newpost); 
                                  }
                                  
                                } else {

                                  errorfunc.call(thisResource,{
                                    message: "Signature of retwisted post could not be verified.",
                                    code: 32062
                                  });
                                
                                }
                              
                            });
                            
                          });
                          
                        } else {

						  if (cbfunc && signatureVerification=="instant") { cbfunc(newpost); }
                          
                        }

					} else {

                        errorfunc.call(thisResource,{
                          message: "Post signature could not be verified.",
                          code: 32060
                        });

					}

				});

			});
				
		}
 
    } else if(cbfunc) {
      cbfunc(thisResource._posts[newid]);
    }

}

TwisterStream.prototype._doPost = function (id, cbfunc, querySettings) {

  if (querySettings===undefined) {querySettings={};} 
  
  //console.log(querySettings)
  
  var Twister = this._scope;

  var thisResource = this;
  
  if (id && id>0) {

    if (id in this._posts){

      cbfunc(this._posts[id])

      this._log("post already in cache");

    } else {
        
      thisResource._activeQuerySettings = querySettings;
      thisResource._updateInProgress = true;

      this._log("post "+id+" not in cache");

      var thisResource = this;

      thisResource.fillCache(id,function(success){

        if (success) {

          thisResource._log("fill cache was successfull")
          
          thisResource._activeQuerySettings = {};
          thisResource._updateInProgress = false;

          cbfunc(thisResource._posts[id])

        } else {

          thisResource.dhtget([thisResource._name, "post"+id, "s"],

            function (result) {

              if (result[0]) {
            
                thisResource._verifyAndCachePost(result[0].p.v,cbfunc);
                
              } else {
			
                thisResource._handleError({
                  message: "DHT resource is empty.",
                  code: 32052
                })
                thisResource._updateInProgress = false;
                //cbfunc(null);
                
              }
          
              thisResource._activeQuerySettings = {};
              thisResource._updateInProgress = false;

            }

          ); 

        }

      });

    }

  }
    
};

TwisterStream.prototype._doUntil = function (cbfunc, querySettings) {

  this._checkQueryAndDo(function doUntil(post){

    var retVal = cbfunc(post);

    if( post.getLastId() && retVal!==false ) { 

      post.doPreviousPost(doUntil, querySettings); 

    }

  }, querySettings);
	
}

module.exports = TwisterStream;