'use strict';

var send = require('./lib/sendData');
var revisions = require('./lib/revisions');

var when = require('when');
var bindCallback = require('when/node').bindCallback;
var nodefn = require('when/node');

function challenge(stream, options, cb){
  //if doesnt have a challenge just return
  if(!options.hasOwnProperty('challenge')){
    return cb();
  }
  
  function unspool(index) {
    return [index, index+1];
  }

  function predicate(index) {
    return index >= options.challenge.length ;
  }

  function handler(index) {

    var d = when.defer();

    send(stream, 1000, options.challenge.slice(index, index + 1), function(err, response){
      if(err){ return d.reject(err); }

      if(response !== options.response[index]){
        return d.reject(new Error('Incorrect Response: ', response));
      }

      return d.resolve();
    });

    return d.promise;
  }

  //sigh hes deprecating this too
  //https://github.com/cujojs/when/issues/370
  //https://github.com/cujojs/when/issues/272
  var promsie = when.unfold(unspool, predicate, handler, 0);
  nodefn.bindCallback(promsie, cb);
}

function identifyBS2(stream, options, cb) {
  return bindCallback(when.promise(function(resolve, reject) {

    var lookup = nodefn.lift(options.lookup);

    var ch = nodefn.lift(challenge);

    function version(){
      var d = when.defer();

      send(stream, 1000, options.version, function(err, result){
        if(err){ return d.reject(err); }

        return d.resolve(result);
      });

      return d.promise;
    }

    ch(stream, options)
    .then(version)
    .then(lookup)
    //this is really dumb
    .done(
      function(result){
        return resolve(result);
      },
      function(error){
        return reject(error);
      });

  }), cb);
}

function bootload(stream, hex, cb){
  return bindCallback(when.promise(function(resolve, reject) {

    //partially applying deprecated, so then how do you late bind?
    //https://github.com/cujojs/when/issues/313

    //and if I did then how would I get the version through then?
    function upload(version){
      var d = when.defer();

      send(stream, 1000, hex, function(err, result){
        if(err){ return d.reject(err); }

        return d.resolve(version);
      });

      return d.promise;
    }

    function signoff(version){
      var d = when.defer();

      stream.write(new Buffer([0]), function(err, result){
        if(err){ return d.reject(err); }

        return d.resolve(version);
      });

      return d.promise;
    }

    identifyBS2(stream, revisions.bs2)
    .then(upload)
    .then(signoff)
    //this is really dumb
    .done(
      function(result){
        return resolve(result);
      },
      function(error){
        return reject(error);
      });

  }), cb);
}

module.exports = {
  identifyBS2: identifyBS2,
  bootload: bootload,
  revisions: revisions
};

@@ -1017,18 +1017,18 @@
 var prom
-s
 i
+s
 e = when
@@ -1070,16 +1070,23 @@
 , 0);%0A  
+return 
 nodefn.b
@@ -1101,18 +1101,18 @@
 ack(prom
-s
 i
+s
 e, cb);%0A
@@ -1161,156 +1161,8 @@
 b) %7B
-%0A  return bindCallback(when.promise(function(resolve, reject) %7B%0A%0A    var lookup = nodefn.lift(options.lookup);%0A%0A    var ch = nodefn.lift(challenge);
 %0A%0A  
@@ -1399,18 +1399,39 @@
  %7D%0A%0A    
-ch
+var promise = challenge
 (stream,
@@ -1473,293 +1473,121 @@
 hen(
-lookup)%0A    //this is really dumb%0A    .done(%0A      function(result)%7B%0A        return resolve(result);%0A      %7D,%0A      function(error)%7B%0A        return reject(error);%0A      %7D);%0A%0A  %7D), cb);%0A%7D%0A%0Afunction bootload(stream, hex, cb)%7B%0A  return bindCallback(when.promise(function(resolve, reject) 
+nodefn.lift(options.lookup));%0A%0A    return nodefn.bindCallback(promise, cb);%0A%7D%0A%0Afunction bootload(stream, hex, cb)
 %7B%0A%0A 
@@ -2239,16 +2239,30 @@
   %7D%0A%0A   
+ var promise =
  identif
@@ -2329,179 +2329,49 @@
 off)
-%0A    //this is really dumb%0A    .done(%0A      function(result)%7B%0A        return resolve(result);%0A      %7D,%0A      function(error)%7B%0A        return reject(error);%0A      %7D);%0A%0A  %7D)
+;%0A%0A    return nodefn.bindCallback(promise
 , cb

return nodefn.bindCallback