/**
 * Adaptive benchmarking. Starts with `initialTimes` iterations, increasing by
 * a power of two each time until the benchmark takes at least `minDuration_ms`
 * milliseconds to complete.
 */

var Canvas = require('../lib/canvas')
  , canvas = new Canvas(200, 200)
  , largeCanvas = new Canvas(1000, 1000)
  , ctx = canvas.getContext('2d');

var initialTimes = 10;
var minDuration_ms = 2000;

var queue = [], running = false;

function bm(label, fn) {
  queue.push({label: label, fn: fn});
  next();
}

function next() {
  if (queue.length && !running) {
    run(queue.pop(), initialTimes, Date.now());
  }
}

function run(benchmark, n, start) {
  running = true;
  var originalN = n;
  var fn = benchmark.fn;
  if (fn.length) { // async
    var pending = n;
    while (n--) fn(function () {
      --pending || done(benchmark, originalN, start, true);
    });
  } else {
    while (n--) fn();
    done(benchmark, originalN, start);
  }
}

function done(benchmark, times, start, async) {
  var duration = Date.now() - start;
  if (duration < minDuration_ms) {
    run(benchmark, times * 2, Date.now());
  } else {
    var opsSec = times / duration * 1000
    if (async) {
      console.log('  - \x1b[33m%s\x1b[0m %s ops/sec (%s times, async)', benchmark.label, opsSec.toLocaleString(), times);
    } else {
      console.log('  - \x1b[33m%s\x1b[0m %s ops/sec (%s times)', benchmark.label, opsSec.toLocaleString(), times);
    }
    running = false;
    next();
  }
}

// node-canvas

bm('lineTo()', function(){
  ctx.lineTo(0, 50);
});

bm('arc()', function(){
   ctx.arc(75,75,50,0,Math.PI*2,true);
});

bm('fillStyle= hex', function(){
  ctx.fillStyle = '#FFCCAA';
});

bm('fillStyle= rgba()', function(){
  ctx.fillStyle = 'rgba(0,255,80,1)';
});

// Apparently there's a bug in cairo by which the fillRect and strokeRect are
// slow only after a ton of arcs have been drawn.
bm('fillRect()', function(){
  ctx.fillRect(50, 50, 100, 100);
});

bm('strokeRect()', function(){
  ctx.strokeRect(50, 50, 100, 100);
});

bm('linear gradients', function(){
  var lingrad = ctx.createLinearGradient(0,50,0,95);
  lingrad.addColorStop(0.5, '#000');
  lingrad.addColorStop(1, 'rgba(0,0,0,0)');
  ctx.fillStyle = lingrad;
  ctx.fillRect(10,10,130,130);
});

bm('toBuffer() 200x200', function(){
  canvas.toBuffer();
});

bm('toBuffer() 1000x1000', function(){
  largeCanvas.toBuffer();
});

bm('toBuffer() async 200x200', function(done){
  canvas.toBuffer(function (err, buf) {
    done();
  });
});

bm('toBuffer() async 1000x1000', function(done){
  largeCanvas.toBuffer(function (err, buf) {
    done();
  });
});

bm('toBuffer().toString("base64") 200x200', function(){
  canvas.toBuffer().toString('base64');
});

bm('toDataURL() 200x200', function(){
  canvas.toDataURL();
});

bm('moveTo() / arc() / stroke()', function(){
  ctx.beginPath();
  ctx.arc(75,75,50,0,Math.PI*2,true); // Outer circle
  ctx.moveTo(110,75);
  ctx.arc(75,75,35,0,Math.PI,false);   // Mouth
  ctx.moveTo(65,65);
  ctx.arc(60,65,5,0,Math.PI*2,true);  // Left eye
  ctx.moveTo(95,65);
  ctx.arc(90,65,5,0,Math.PI*2,true);  // Right eye
  ctx.stroke();
});

bm('createImageData(300,300)', function(){
  ctx.createImageData(300,300);
});

bm('getImageData(0,0,100,100)', function(){
  ctx.getImageData(0,0,100,100);
});

bm('PNGStream 200x200', function(done){
  var stream = canvas.createSyncPNGStream();
  stream.on('data', function(chunk){
    // whatever
  });
  stream.on('end', function(){
    done();
  });
});