var express = require('express')
var app = express.createServer()
var http = require('http')
var fs = require('fs')
var QRCode = require('../lib')
var canvasutil = require('canvasutil')
var Canvas = require('canvas')
var Image = Canvas.Image

var path = require('path')

app.configure(function () {
  app.use(express.methodOverride())
  app.use(express.bodyParser())
  app.use(app.router)
  app.use(express.static(path.resolve(__dirname, '..')))
})

app.get('/', function (req, res) {
  fs.readFile(path.join(__dirname, 'clientside.html'), function (err, data) {
    res.send(data ? data.toString() : err)
  })
})

var effectHandlers = {}

app.get('/generate', function (req, res) {
  var q = req.query || {}

  QRCode.QRCodeDraw.color.light = q.lightColor || '#ffffff'
  QRCode.QRCodeDraw.color.dark = q.darkColor || '#000000'
  QRCode.QRCodeDraw.scale = +(q.scale)

  if (isNaN(QRCode.QRCodeDraw.scale)) QRCode.QRCodeDraw.scale = 4
  // NOTE when i set scale to 500 something seg faulted
  if (QRCode.QRCodeDraw.scale > 50) QRCode.QRCodeDraw.scale = 50

  var effect = q.effect || 'plain'
  if (!effectHandlers[effect]) {
    effect = 'plain'
  }

  effectHandlers[effect](q, function (error, canvas) {
    if (!error) {
      canvas.toBuffer(function (err, buf) {
        if (!err) {
          res.header('Content-Type', 'image/png')
          res.send(buf)
        }
      })
    } else {
      var msg = error.message + '\n' + error.stack
      res.header('Content-Type', 'text/plain')
      res.send(msg)
      console.error(msg)
    }
  })
})

effectHandlers.node = function (args, cb) {
  args.src = path.join(__dirname, 'images', 'node_logo.png')
  this.image(path.join(args, cb))
}

effectHandlers.npm = function (args, cb) {
  args.src = path.join(__dirname, 'images', 'npm_logo.png')
  this.image(args, cb)
}

effectHandlers.bacon = function (args, cb) {
  args.src = path.join(__dirname, 'images', 'bacon-love.png')
  this.image(args, cb)
}

effectHandlers.baconBikini = function (args, cb) {
  args.src = path.join(__dirname, 'images', 'bacon-bikini.png')
  this.image(args, cb)
}

effectHandlers.rounded = function (args, cb) {
  QRCode.draw(args.text || '', function (err, canvas) {
    if (err) {
      cb(err, canvas)
      return
    }

    var tpx = new canvasutil.PixelCore()
    var luma709Only = canvasutil.conversionLib.luma709Only
    var up = []
    var down = []
    var left = []
    var right = []
    var upPx
    var downPx
    var leftPx
    var rightPx
    var r
    var t
    var l
    var d
    var corner = 0

    tpx.threshold = 100

    tpx.iterate(canvas, function (px, i, len, pixels, w, h, pixelCore) {
      corner = 0

      // is dark
      if (luma709Only(px.r, px.g, px.b) < pixelCore.threshold) {
        if (i - w > 0) {
          upPx = (i - w) * 4
          up[0] = pixels[upPx + 0]
          up[1] = pixels[upPx + 1]
          up[2] = pixels[upPx + 2]
          // console.log('up',up);
        }

        if (i + w <= len) {
          downPx = (i + w) * 4
          down[0] = pixels[downPx + 0]
          down[1] = pixels[downPx + 1]
          down[2] = pixels[downPx + 2]
          // console.log('down',down);
        }

        // have left pixel but no wrapping
        if (i % w !== 0) {
          leftPx = (i - 1) * 4
          left[0] = pixels[leftPx + 0]
          left[1] = pixels[leftPx + 1]
          left[2] = pixels[leftPx + 2]
          // console.log('left',left);
        }

        if (i % w !== w - 1) {
          rightPx = (i + 1) * 4
          right[0] = pixels[rightPx + 0]
          right[1] = pixels[rightPx + 1]
          right[2] = pixels[rightPx + 2]
          // console.log('right',right);
        }

        r = rightPx ? luma709Only(right[0], right[1], right[2]) : 0
        t = upPx ? luma709Only(up[0], up[1], up[2]) : 0
        l = leftPx ? luma709Only(left[0], left[1], left[2]) : 0
        d = downPx ? luma709Only(down[0], down[1], down[2]) : 0

        if (l > pixelCore.threshold) { // if left is light and i am dark
          if (t > pixelCore.threshold) { // if top is light and i am dark
            corner = 1
            pixels[rightPx + 4] = 100
          } else if (d > pixelCore.threshold) { // if bottom is light and i am dark
            pixels[rightPx + 4] = 100
            corner = 1
          }
        } else if (r > pixelCore.threshold) {
          if (t > pixelCore.threshold) { // if top is light and i am dark
            corner = 1
          } else if (d > pixelCore.threshold) { // if bottom is light and i am dark
            corner = 1
          }
        }

        if (corner) {
          px.a = 50
        }
      }
    })
    cb(false, canvas)
  })
}

effectHandlers.remoteImage = function (args, cb) {
  var src = args.src
  var domain
  var uri

  if (!src) {
    cb(new Error('src required'), null)
  } else {
    if (src.indexof('://') !== -1) {
      src = src.split('://').unshift()
      var parts = src.split('/')

      domain = parts.shift()
      uri = parts.join('/')
    }
  }

  if (!domain || !uri) {
    cb(new Error('missing domain or uri ' + args.src))
    return
  }

  var options = {
    host: domain,
    port: 80,
    path: uri,
    method: 'GET'
  }

  var req = http.request(options, function (res) {
    if (res.statusCode < 200 || res.statusCode > 299) {
      cb(new Error('http ' + res.statusCode + ' response code'), null)
      return
    }

    res.setEncoding('utf8')

    var data = ''
    res.on('data', function (chunk) {
      data += chunk
      console.log('BODY: ' + chunk)
    })

    res.on('complete', function () {
      cb(false, data)
    })

    res.on('error', function (error) {
      cb(error, null)
      cb = function () {}
    })
  })

  req.end()
}

effectHandlers.image = function (args, cb) {
  var src = args.src || ''

  var img = new Image()
  var convert = canvasutil.conversionLib
  img.onload = function () {
    QRCode.draw(args.text || '', function (err, canvas) {
      if (err) {
        cb(err, false)
        return
      }

      var codeCtx = canvas.getContext('2d')
      var frame = codeCtx.getImageData(0, 0, canvas.width, canvas.width)
      var tpx = new canvasutil.PixelCore()
      var baconCanvas = new Canvas(canvas.width, canvas.width)
      var ctx = baconCanvas.getContext('2d')
      var topThreshold = args.darkThreshold || 25
      var bottomThreshold = args.lightThreshold || 75

      tpx.threshold = 50

      // scale image
      var w = canvas.width
      var h = canvas.height

      if (img.width > img.height) {
        w = w * (canvas.height / h)
        h = canvas.height
      } else {
        h = h * (canvas.height / w)
        w = canvas.width
      }
      ctx.drawImage(img, 0, 0, w, h)

      try {
        tpx.iterate(baconCanvas, function (px, i, l, pixels, w, h, pixelCore) {
          var luma = (0.2125 * px.r + 0.7154 * px.g + 0.0721 * px.b)
          var codeLuma = convert.luma709Only(frame.data[i * 4], frame.data[i * 4 + 1], frame.data[i * 4 + 2])
          var yuv
          var rgb

          if (codeLuma > pixelCore.threshold) {
            if (luma < bottomThreshold) {
              yuv = convert.rgbToYuv(px.r, px.g, px.b)
              rgb

              rgb = convert.yuvToRgb(bottomThreshold, yuv[1], yuv[2])

              px.r = rgb[0]
              px.g = rgb[1]
              px.b = rgb[2]
              px.a = 255
            }
          } else {
            if (luma > topThreshold) {
              yuv = convert.rgbToYuv(px.r, px.g, px.b)

              rgb = convert.yuvToRgb(topThreshold, yuv[1], yuv[2])

              px.r = rgb[0]
              px.g = rgb[1]
              px.b = rgb[2]
            }
          }
        })
      } catch (e) {
        cb(err, false)
      }

      cb(false, baconCanvas)
    })
  }

  img.onerror = function (error) {
    error.message += ' (' + src + ')'
    cb(error, null)
  }

  img.src = src
}

effectHandlers.plain = function (args, cb) {
  var text = args.text || ''
  QRCode.draw(text || '', function (err, canvas) {
    cb(err, canvas)
  })
}

app.listen(3031)
console.log('listening on 3031')