package org.ourfilesystem.filehander;

/*
OurFileSystem is a peer2peer file sharing program.
Copyright (C) 2012  Robert Gass

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

*/

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.LinkedList;
import java.util.List;

public class FileSplitter {
	
	/*
	 * NOTE: If we limit the piece sizes to 2MB, then that means we can record
	 * up to about 29000 pieces for a given file (512Hash plus 2 long values is 72 bytes).  
	 * So that's a max file size of almost 60GB.  So 100GB limit on the splitter is plenty.
	 */
	public static long MAXFILESIZE = 100L * 1024L * 1024L * 1024L; //100GB
	
	public static List<File> split(File f, File tmpdir, long size) throws IOException {
		LinkedList<File> rl = new LinkedList<File>();
		FileInputStream fis = new FileInputStream(f);
		FileChannel fic = fis.getChannel();
		long remainlen = fic.size();
		long pos = 0;
		while (remainlen > 0) {
			File nf = File.createTempFile("peice", ".dat", tmpdir);
			rl.add(nf);
			FileOutputStream fos = new FileOutputStream(nf);
			FileChannel foc = fos.getChannel();
			ByteBuffer buf = ByteBuffer.allocate(2*(Long.SIZE/Byte.SIZE));
			
			long transfersize = Math.min(remainlen, size);
			remainlen -= transfersize;
			buf.putLong(pos);
			buf.putLong(transfersize);
			buf.clear();
			while (buf.hasRemaining()) {
				foc.write(buf);
			}
			
			long wrlen = fic.transferTo(pos, transfersize, foc);
			while (wrlen < transfersize) {
				transfersize -= wrlen;
				pos += wrlen;
				wrlen = fic.transferTo(pos, transfersize, foc);
			}
			pos += wrlen;
			
			foc.close();
		}
		fic.close();
		return rl;
	}
	
	public static void insert(File fullfile, File peice) throws IOException {
		RandomAccessFile raf = new RandomAccessFile(fullfile, "rw");
		FileChannel foc = raf.getChannel();
		FileInputStream fis = new FileInputStream(peice);
		FileChannel fic = fis.getChannel();
		ByteBuffer buf = ByteBuffer.allocate(2*(Long.SIZE/Byte.SIZE));
		while (buf.hasRemaining()) {
			fic.read(buf);
		}
		buf.clear();
		long pos = buf.getLong();
		long size = buf.getLong();
		if ((pos+size) > MAXFILESIZE) {
			throw new IOException("Cannot create file this large.");
		}
		if (size != (fic.size()-fic.position())) {
			throw new IOException("File peice corrupted.");
		}
		foc.position(pos);
		buf = ByteBuffer.allocateDirect(1024);
		while (size > 0) {
			fic.read(buf);
			buf.flip();
			foc.write(buf);
			size -= buf.position();
			buf.compact();
		}
		foc.close();
		fic.close();
	}

}
