/**
 * A set of UPC validation functions all under the namespace of Upc.
 *
 * + is_valid
 * + flesh_out
 * - is_missing_checksum
 * - pad
 * - get_checksum_digit
 */

function Upc() {
}

/**
 * @return true iff the UPC is a valid, standard UPC.
 */
Upc.is_valid = function(upc) {
  upc = YAHOO.lang.trim(upc);
  if( !/^[0-9]+$/.test(upc) ) {
    // This isn't a string of numbers!
    return false;
  }

  upc = Upc.pad(upc);

  var length = upc.length;

  var checksumDigit = Upc.get_checksum_digit(upc);
  if( checksumDigit < 0 ) {
    return false;
  }

  if( length == 11 ) {
    upc += checksumDigit;
    return true;
  } else if( length == 12 ) {
    // Check the checksum.
    if( checksumDigit != upc[11] ) {
      return false;
    } else {
      // We don't have any reason to believe this UPC is invalid.
      return true;
    }
  }

  // We can't handle this UPC.
  return false;
}

/**
 * Prefixes the UPC with a 0 if necessary and appends the checksum digit if it is missing.
 */
Upc.flesh_out = function(upc) {
  if( !Upc.is_valid(upc) ) {
    return false;
  }

  upc = Upc.pad(upc);

  if( Upc.is_missing_checksum(upc) ) {
    var checksum = Upc.get_checksum_digit(upc);
    if( checksum < 0 ) {
      return false;
    }
    upc += checksum;
  }

  return upc;
}

/**
 * Assumes that the UPC has been padded.
 */
Upc.is_missing_checksum = function(upc) { 
  var length = upc.length;

  if( length == 10 || length == 11 ) {
    return true;
  }

  return false;
}

/**
 * Pad the UPC with 0s.  If the UPC is in short form, pad with the respective digits.
 */
Upc.pad = function(upc) {
  var length = upc.length;

  if( length == 10 ) {
    upc = '0' + upc;
  } else if( length == 6 || length == 7 && upc[0] == '0' ) {
    if( length == 7 ) {
      upc = upc.substr(1);
    }
    var last = parseInt(upc[5]);
    switch( last ) {
      case 0:
      case 1:
      case 2:
        upc = '0' + upc.substr(0, 2) + last + '0000' + upc.substr(2, 3);
        break;
      case 3:
        upc = '0' + upc.substr(0, 3) + '00000' + upc.substr(3, 2);
        break;
      case 4:
        upc = '0' + upc.substr(0, 4) + '00000' + upc.substr(4, 1);
        break;
      case 5:  
      case 6:
      case 7:
      case 8:
      case 9:
        upc = '0' + upc.substr(0, 5) + '00005';
        break;
    }
  }

  return upc;
}

/**
 * If the upc is from a user, they've likely left out the checksum.
 * If the upc is from the DB, it's likely missing the leading 0.
 * @return the last digit (the checksum) of this UPC code.
 */
Upc.get_checksum_digit = function(upc) {
  upc = Upc.pad(upc);
  var length = upc.length;

  var odd = 0;
  var even = 0;

  if( length == 11 || length == 12 ) {
    // Generate a checksum of the first 11 digits.
    for( index = 0; index < 11; index++ ) {
      if( index % 2 == 0 ) {
        // Odd.
        odd += parseInt(upc[index]);
      } else {
        // Even.
        even += parseInt(upc[index]);
      }
    }
    var total = 3 * odd + even;
    var lastdigit = total % 10;
    var checksumDigit = 0;
    if( lastdigit ) {
      checksumDigit = 10 - lastdigit;
    }

    return checksumDigit;
  }

  return -1;
}
