package org.torrent.internal.data;
import java.util.Iterator;
import org.torrent.internal.util.Range;
import org.torrent.internal.util.Validator;
public class TorrentMetaInfo implements Iterable<TorrentMetaInfo.Piece> {
private final long length;
private final int pieceLength;
private final Hash infoHash;
private final Piece[] piece;
public final class Piece {
private final Hash hash;
private final int index;
public Piece(int index, Hash hash) {
assert hash != null;
this.index = index;
this.hash = hash;
}
public long getStart() {
return (long) pieceLength * index;
}
public Hash getHash() {
return hash;
}
public int getIndex() {
return index;
}
public int getLength() {
return (int) Math.min(pieceLength, length - getStart());
}
public BTPart asBTPart() {
return new BTPart(index, 0, getLength());
}
/**
* @return the absolute range within the data
*/
public Range getRange() {
long start = getStart();
return Range.getRangeByLength(start, Math.min(length - start,
pieceLength));
}
public TorrentMetaInfo getContentInfo() {
return TorrentMetaInfo.this;
}
@Override
public String toString() {
return "Piece " + index + ", range = " + getRange() + ", hash = "
+ hash;
}
}
public TorrentMetaInfo(Hash infoHash, Hash[] hashes, long length,
int pieceLength) {
Validator.nonNull(infoHash);
Validator.isTrue(length >= 0, "Invalid length: " + length);
Validator.isTrue(pieceLength > 0, "Invalid piece length: " + length);
Validator.isTrue(infoHash.getType() == Hash.Type.SHA1,
"Wrong hash type: " + infoHash);
this.length = length;
this.pieceLength = pieceLength;
int piecesCount = (int) ((length + pieceLength - 1) / pieceLength);
Validator.isTrue(piecesCount == hashes.length,
"Wrong number of hashes: " + hashes.length + ", expected "
+ piecesCount);
piece = new Piece[piecesCount];
this.infoHash = infoHash;
for (int i = 0; i < piecesCount; i++) {
piece[i] = new Piece(i, hashes[i]);
}
}
public long getLength() {
return length;
}
public int getPieceLength() {
return pieceLength;
}
public int getPiecesCount() {
return piece.length;
}
public Range asRange() {
return Range.getRangeByLength(0, length);
}
public Range getAbsoluteRange(BTPart pi) {
Range result = Range.getRangeByLength(getAbsoluteStart(pi), pi
.getLength());
Validator.isTrue(result.getEnd() <= length,
"Part length exceeds content range!");
return result;
}
public long getAbsoluteStart(BTPart pi) {
return piece[pi.getIndex()].getStart() + pi.getStart();
}
public Hash getInfoHash() {
return infoHash;
}
public Piece getPiece(int pieceIndex) {
return piece[pieceIndex];
}
@Override
public Iterator<Piece> iterator() {
return new Iterator<Piece>() {
private int index = 0;
@Override
public boolean hasNext() {
return index < piece.length;
}
@Override
public Piece next() {
return piece[index++];
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public boolean isPrivate() {
return false;
}
}