private TorrentMapping (List<TorrentFileInfo> files, long pieceSize) {
        List<Entry> allMappings = new ArrayList<Entry>(files.size());
        List<Path> allFiles = new ArrayList<Path>(files.size());
        final List<List<Entry>> pToF = new ArrayList<List<Entry>>();
        final Map<Path,List<Entry>> fToP = new HashMap<Path,List<Entry>>();

        int numPieces = 0;

        long remPieceLen = pieceSize;
        long initPiecePos = 0;

        List<Entry> thisPieceMappings = new ArrayList<Entry>();

        for (TorrentFileInfo file : files) {
            List<Entry> thisFileMappings = new ArrayList<Entry>((int) (file.getLength() / pieceSize + 1));

            long remFileLen = file.getLength();
            long initFilePos = 0;

            // While this file is not fully mapped...
            while (remFileLen > 0) {

                // If the remaining piece fits entirely in this file...
                if (remFileLen >= remPieceLen) {
                    Entry entry =
                        new Entry(numPieces, new PositionRange(initPiecePos, (initPiecePos + remPieceLen)), file
                            .getPath(), new PositionRange(initFilePos, (initFilePos + remPieceLen)));
                    allMappings.add(entry);
                    thisFileMappings.add(entry);
                    thisPieceMappings.add(entry);

                    remFileLen -= remPieceLen;
                    initFilePos += remPieceLen;

                    remPieceLen = pieceSize;
                    initPiecePos = 0;

                    numPieces++;
                    pToF.add(thisPieceMappings);
                    thisPieceMappings = new ArrayList<Entry>();
                } else {
                    Entry entry =
                        new Entry(numPieces, new PositionRange(initPiecePos, (initPiecePos + remFileLen)), file
                            .getPath(), new PositionRange(initFilePos, (initFilePos + remFileLen)));
                    allMappings.add(entry);
                    thisFileMappings.add(entry);
                    thisPieceMappings.add(entry);

                    remPieceLen -= remFileLen;
                    initPiecePos += remFileLen;

                    remFileLen = 0;
                }

            }

            allFiles.add(file.getPath());
            fToP.put(file.getPath(), thisFileMappings);
        }

        // If the last piece was not of regular size...
        if (remPieceLen < pieceSize) {
            numPieces++;
            pToF.add(thisPieceMappings);
        }

        pieceCount = numPieces;
        piecesToFiles = Collections.unmodifiableList(pToF);
        filesToPieces = Collections.unmodifiableMap(fToP);
        fileList = Collections.unmodifiableList(allFiles);
        mappings = Collections.unmodifiableList(allMappings);
    }