"use strict";

var utils = require("./utils.js");
function DataReader() {
  this.data = null; // type : see implementation
  this.length = 0;
  this.index = 0;
  this.zero = 0;
}
DataReader.prototype = {
  /**
   * Check that the offset will not go too far.
   * @param {string} offset the additional offset to check.
   * @throws {Error} an Error if the offset is out of bounds.
   */
  checkOffset: function checkOffset(offset) {
    this.checkIndex(this.index + offset);
  },
  /**
   * Check that the specifed index will not be too far.
   * @param {string} newIndex the index to check.
   * @throws {Error} an Error if the index is out of bounds.
   */
  checkIndex: function checkIndex(newIndex) {
    if (this.length < this.zero + newIndex || newIndex < 0) {
      throw new Error("End of data reached (data length = " + this.length + ", asked index = " + newIndex + "). Corrupted zip ?");
    }
  },
  /**
   * Change the index.
   * @param {number} newIndex The new index.
   * @throws {Error} if the new index is out of the data.
   */
  setIndex: function setIndex(newIndex) {
    this.checkIndex(newIndex);
    this.index = newIndex;
  },
  /**
   * Skip the next n bytes.
   * @param {number} n the number of bytes to skip.
   * @throws {Error} if the new index is out of the data.
   */
  skip: function skip(n) {
    this.setIndex(this.index + n);
  },
  /**
   * Get the byte at the specified index.
   * @param {number} i the index to use.
   * @return {number} a byte.
   */
  byteAt: function byteAt() {
    // see implementations
  },
  /**
   * Get the next number with a given byte size.
   * @param {number} size the number of bytes to read.
   * @return {number} the corresponding number.
   */
  readInt: function readInt(size) {
    var result = 0,
      i;
    this.checkOffset(size);
    for (i = this.index + size - 1; i >= this.index; i--) {
      result = (result << 8) + this.byteAt(i);
    }
    this.index += size;
    return result;
  },
  /**
   * Get the next string with a given byte size.
   * @param {number} size the number of bytes to read.
   * @return {string} the corresponding string.
   */
  readString: function readString(size) {
    return utils.transformTo("string", this.readData(size));
  },
  /**
   * Get raw data without conversion, <size> bytes.
   * @param {number} size the number of bytes to read.
   * @return {Object} the raw data, implementation specific.
   */
  readData: function readData() {
    // see implementations
  },
  /**
   * Find the last occurence of a zip signature (4 bytes).
   * @param {string} sig the signature to find.
   * @return {number} the index of the last occurence, -1 if not found.
   */
  lastIndexOfSignature: function lastIndexOfSignature() {
    // see implementations
  },
  /**
   * Get the next date.
   * @return {Date} the date.
   */
  readDate: function readDate() {
    var dostime = this.readInt(4);
    return new Date((dostime >> 25 & 0x7f) + 1980,
    // year
    (dostime >> 21 & 0x0f) - 1,
    // month
    dostime >> 16 & 0x1f,
    // day
    dostime >> 11 & 0x1f,
    // hour
    dostime >> 5 & 0x3f,
    // minute
    (dostime & 0x1f) << 1); // second
  }
};

module.exports = DataReader;