package ftp_client;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.util.concurrent.Semaphore;

// Tache de upload de fichier, herite de la classe Task
// Classe sensiblement identique a DownloadTask, je ne reprends donc pas tous les commentaires ici
public class UploadTask extends Task {

	// Buffer Size
	final static int BUFFER_SIZE = 1024 *32;

	// Shared commands FTP connection
	private static Semaphore s = new Semaphore(0); {s.release();}
	private static FTP free_ftp = null;
	
	// Current and base FTP connection
	private FTP 	ftp, oftp;

	/* Constructor */
	public UploadTask(Scheduler scheduler, FTP ftp, String srcFile, String dstFile, String rmtPath, long offset) throws Exception {
		super(scheduler);
		this.oftp = ftp;
		this.srcFile = srcFile;
		this.dstFile = dstFile;
		this.rmtPath = rmtPath;
		this.bytesSent = (offset>0?offset:0);
		this.fileSize = 0;
	}

	/* Task's Work */
	protected void doWork(){
		File f;
		
		try{
			f = new File(srcFile);
			if(f.isDirectory()) throw new Exception("Impossible d'uploader un repertoire"); 
			
			fileSize = f.length();
			
			// Flux d'entree depuis un fichier
			BufferedInputStream input = new BufferedInputStream(new FileInputStream(srcFile));
			
			// On evite les bytesSent octets deja envoyes
			input.skip(bytesSent);
			
			s.acquire();
			try{
				if(free_ftp != null){
					ftp = free_ftp;
					free_ftp = null;
				}else{
					ftp = new FTP();
					ftp.connect(oftp);
				}
			}catch(Exception e){ s.release(); throw e; }
			s.release();
			boolean needToAbort = false;
			
			ftp.cwd(rmtPath);
			
			ftp.bin();
			
			MSocket dataSocket = ftp.PASV();
			
			String response="";
			
			// Commande d'envoi de fichier
		    if(bytesSent == 0) response = ftp.command("STOR \""+ dstFile+"\""); // STOR si on part de zero
		    else			   response = ftp.command("APPE \""+ dstFile+"\""); // APPE si on reprend un upload
		   
		    if (!response.startsWith ("125") && !response.startsWith("150"))
		      throw new Exception(response);
		    
		    needToAbort = true;
		    
		    OutputStream output = dataSocket.getOutputStream();

		    byte[] buffer = new byte[BUFFER_SIZE];
		    int bytesRead = 0;
		    
		    while (!(stopped = hasToStop()) && bytesSent < fileSize && ((bytesRead = input.read(buffer)) != -1)){
		    	output.write(buffer, 0, bytesRead);
		    	bytesSent += bytesRead;
		    }
		    
		    stopped = (bytesSent < f.length());
		    
		    if (stopped && needToAbort){
		    	ftp.readAllText(); // flush
		    	response = ftp.command("ABOR");
			    while(!response.startsWith("226") && !response.startsWith("225"))
			    	response = ftp.readLine();
		    }
		    		    
		    output.flush();
			output.close();
		    input.close();
		    
		    dataSocket.close();
		    
		    s.acquire();
		    free_ftp = ftp;
		    s.release();
		    
		    if(stopped && !hasToStop()) throw new Exception("Problème de transfert.");
		} catch (Exception e) {
			
			stopped = true;
			aborted = (++ExceptionCount) == MaxExceptionCount;
			if(!aborted){
				int remaining = (MaxExceptionCount-ExceptionCount);
				String pluriel = remaining>1?"s":""; 
				Message.sendError("Erreur lors de l'upload de \""+srcFile+"\".\n"+e.getMessage()+"\nProchaine tentative dans 3 secondes. ("+remaining+" tentative"+pluriel+" restante"+pluriel+")");
				try {
					Thread.sleep(3000);
				} catch (InterruptedException e1) {}
			}else{
				Message.sendError("Impossible d'uploader \""+srcFile+"\".");
			}
			if(aborted) fireAbortedListener(this);
		}
	}

}
