'use strict';


var ParserStream = require('../common').ParserStream;


// part of parseJpegMarker called after skipping initial FF
function parseJpegMarker_afterFF(parser, callback) {
  parser._bytes(1, function (data) {
    var code = data[0];

    if (code === 0xFF) {
      // padding byte, skip it
      parseJpegMarker_afterFF(parser, callback);
      return;
    }

    // standalone markers, according to JPEG 1992,
    // http://www.w3.org/Graphics/JPEG/itu-t81.pdf, see Table B.1
    if ((0xD0 <= code && code <= 0xD9) || code === 0x01) {
      callback(code, 0);
      return;
    }

    // the rest of the unreserved markers
    if (0xC0 <= code && code <= 0xFE) {
      parser._bytes(2, function (length) {
        callback(code, length.readUInt16BE(0) - 2);
      });
      return;
    }

    // unknown markers
    callback();
  });
}


function parseJpegMarker(parser, callback) {
  parser._bytes(1, function (data) {
    if (data[0] !== 0xFF) {
      // not a JPEG marker
      callback();
      return;
    }

    parseJpegMarker_afterFF(parser, callback);
  });
}


function getJpegSize(parser) {
  parseJpegMarker(parser, function (code, length) {
    if (!code || length < 0) {
      // invalid jpeg
      parser._skipBytes(Infinity);
      parser.push(null);
      return;
    }

    if (code === 0xD9 /* EOI */ || code === 0xDA /* SOS */) {
      // end of the datastream
      parser._skipBytes(Infinity);
      parser.push(null);
      return;
    }

    if (length <= 0) {
      // e.g. empty comment
      getJpegSize(parser);
      return;
    }

    if (length >= 5 &&
        (0xC0 <= code && code <= 0xCF) &&
        code !== 0xC4 && code !== 0xC8 && code !== 0xCC) {

      parser._bytes(length, function (data) {
        parser._skipBytes(Infinity);

        parser.push({
          width:  data.readUInt16BE(3),
          height: data.readUInt16BE(1),
          type: 'jpg',
          mime: 'image/jpeg',
          wUnits: 'px',
          hUnits: 'px'
        });

        parser.push(null);
      });
      return;
    }

    parser._skipBytes(length, function () {
      getJpegSize(parser);
    });
  });
}


module.exports = function () {
  var parser   = new ParserStream();

  parser._bytes(2, function (data) {
    if (data[0] !== 0xFF || data[1] !== 0xD8) {
      // first marker of the file MUST be 0xFFD8
      parser._skipBytes(Infinity);
      parser.push(null);
      return;
    }

    getJpegSize(parser);
  });

  return parser;
};