var pull = require('pull-stream')

var Handshake = require('pull-handshake')
var State = require('./state')

var challenge_length = 64
var client_auth_length = 16+32+64
var server_auth_length = 16+64
var mac_length = 16

//client is Alice
//create the client stream with the public key you expect to connect to.
exports.client =
exports.createClientStream = function (alice, app_key, timeout) {

  return function (bob_pub, seed, cb) {
    if('function' == typeof seed)
      cb = seed, seed = null

    //alice may be null.
    var state = new State(app_key, alice, bob_pub, seed)

    var stream = Handshake({timeout: timeout}, cb)
    var shake = stream.handshake
    delete stream.handshake

    function abort(err, reason) {
      if(err && err !== true) shake.abort(err, cb)
      else                    shake.abort(new Error(reason), cb)
    }

    shake.write(state.createChallenge())

    shake.read(challenge_length, function (err, msg) {
      if(err) return abort(err, 'challenge not accepted')
      //create the challenge first, because we need to generate a local key
      if(!state.clientVerifyChallenge(msg))
        return abort(null, 'wrong protocol (version?)')

      shake.write(state.createClientAuth())

      shake.read(server_auth_length, function (err, boxed_sig) {
        if(err) return abort(err, 'hello not accepted')

        if(!state.verifyServerAccept(boxed_sig))
          return abort(null, 'server not authenticated')

        cb(null, shake.rest(), state.cleanSecrets())
      })
    })

    return stream
  }
}

//server is Bob.
exports.server =
exports.createServerStream = function (bob, authorize, app_key, timeout) {

  return function (cb) {
    var state = new State(app_key, bob)
    var stream = Handshake({timeout: timeout}, cb)

    var shake = stream.handshake
    delete stream.handshake

    function abort (err, reason) {
      if(err && err !== true) shake.abort(err, cb)
      else                    shake.abort(new Error(reason), cb)
    }

    shake.read(challenge_length, function (err, challenge) {
      if(err) return abort(err, 'expected challenge')
      if(!state.verifyChallenge(challenge))
        return shake.abort(new Error('wrong protocol/version'))

      shake.write(state.createChallenge())
      shake.read(client_auth_length, function (err, hello) {
        if(err) return abort(err, 'expected hello')
        if(!state.verifyClientAuth(hello)) {
          //we know who the client was, but chose not to answer:
          if(state.remote.public)
            return abort(null, 'unauthenticated client:' + state.remote.public.toString('hex'), cb)
          //client dialed wrong number... (we don't know who they where)
          else
            return abort(null, 'wrong number')
        }
        //check if the user wants to speak to alice.
        authorize(state.remote.public, function (err, auth) {
          if(auth == null && !err) err = new Error('client unauthorized')
          if(!auth) return abort(err, 'client authentication rejected')
          state.auth = auth
          shake.write(state.createServerAccept())
          cb(null, shake.rest(), state.cleanSecrets())
        })
      })
    })
    return stream
  }
}




@@ -100,16 +100,86 @@
 /state')
+%0Avar stateless = require('./stateless')%0Avar crypto = require('crypto')
 %0A%0Avar ch
@@ -596,32 +596,125 @@
     var state = 
+stateless.initialize.call(%7B%7D, app_key, alice, bob_pub, crypto.randomBytes(32), seed)%0A      //
 new State(app_ke
@@ -727,24 +727,48 @@
 ce, bob_pub,
+ crypto.randomBytes(32),
  seed)%0A%0A    
@@ -1046,32 +1046,36 @@
 hake.write(state
+less
 .createChallenge
@@ -1074,17 +1074,27 @@
 hallenge
-(
+.call(state
 ))%0A%0A    
@@ -1288,21 +1288,34 @@
     if(!
+(
 state
+ = stateless
 .clientV
@@ -1332,14 +1332,27 @@
 enge
-(
+.call(state, 
 msg))
+)
 %0A   
@@ -1432,26 +1432,40 @@
 tate
-.createClientAuth(
+less.clientCreateAuth.call(state
 ))%0A%0A
@@ -1602,33 +1602,58 @@
 if(!
+(
 state
-.verifyServerAccept(
+ = stateless.clientVerifyAccept.call(state, 
 boxe
@@ -1659,16 +1659,17 @@
 ed_sig))
+)
 %0A       
@@ -1751,38 +1751,53 @@
 est(), state
-.cleanSecrets(
+ = stateless.clean.call(state
 ))%0A      %7D)%0A

use client uses stateless directly