"use strict";

var jpeg = require("jpeg-js")
var png = require("pngparse")
var gif = require("omggif")
var bufferEqual = require("buffer-equal")
var isnumber = require("isnumber")

module.exports = read
module.exports.Image = Image
module.exports.Frame = Frame

var gifHeader = new Buffer("GIF8")
var pngHeader = new Buffer([137, 80, 78, 71])

function read(buffer, callback) {
  // detect type, convert to format
  // braindead logic: check if GIF or PNG, if not, assume JPG
  var head = buffer.slice(0, 4)
  if (bufferEqual(head, gifHeader)) {
    return parseGif(buffer, callback)
  }
  if (bufferEqual(head, pngHeader)) {
    return parsePng(buffer, callback)
  }
  return parseJpg(buffer, callback)
}

function parseGif(buffer, callback) {
  var image
  try {
    image = new gif.GifReader(buffer)
  } catch (e) {
    return callback(e)
  }
  var img = new Image(image.height, image.width)
  var frameCount = image.numFrames()
  for (var i = 0; i < frameCount; i++) {
    var frameInfo = image.frameInfo(i)
    var rgba = new Buffer(frameInfo.width * frameInfo.height * 4)
    image.decodeAndBlitFrameRGBA(i, rgba)
    img.addFrame(rgba, frameInfo.delay * 10)
  }
  return callback(null, img)
}

function parsePng(buffer, callback) {
  png.parse(buffer, function (err, image) {
    if (err) {
      return callback(err)
    }
    var rgba = image.data
    if (image.channels === 1) {
      rgba = new Buffer(image.height * image.width * 4)
      for (var i = 0; i < image.data.length; i++) {
        var idx = i * 4
        rgba[idx] = rgba[idx + 1] = rgba[idx + 2] = image.data[i]
        rgba[idx + 3] = 0xff
      }
    }
    if (image.channels === 2) {
      rgba = new Buffer(image.height * image.width * 4)
      for (var i = 0; i < image.data.length; i += 2) {
        var idx = (i/2) * 4
        rgba[idx] = rgba[idx + 1] = rgba[idx + 2] = image.data[i]
        rgba[idx + 3] = image.data[i + 1]
      }
    }
    if (image.channels === 3) {
      rgba = new Buffer(image.height * image.width * 4)
      for (var i = 0; i < image.data.length; i += 3) {
        var idx = (i/3) * 4
        rgba[idx] = image.data[i]
        rgba[idx + 1] = image.data[i + 1]
        rgba[idx + 2] = image.data[i + 2]
        rgba[idx + 3] = 0xff
      }
    }
    var img = new Image(image.height, image.width)
    img.addFrame(rgba)
    return callback(null, img)
  })
}

function parseJpg(buffer, callback) {
  var image
  try {
    image = jpeg.decode(buffer)
  } catch (e) {
    return callback(e)
  }
  var img = new Image(image.height, image.width)
  img.addFrame(image.data)
  return callback(null, img)
}

function Image(height, width) {
  if (!(this instanceof Image)) {
    return new Image(height, width)
  }
  if (!isnumber(height) || !isnumber(width)) {
    throw new Error("Image height and width must be numbers.")
  }
  this.height = +height
  this.width = +width
  this.frames = []
}
Image.prototype.addFrame = function (rgba, delay) {
  this.frames.push(new Frame(rgba, delay))
}

function Frame(rgba, delay) {
  if (!(this instanceof Frame)) {
    return new Frame(rgba, delay)
  }
  this.data = rgba
  this.delay = delay
}