package com.softgraf.vendas.model.zip;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javafx.scene.control.Label;

/*
 * Compactação de arquivos sem precisar de programas ZIP
 * Muito útil para gerar backups automáticos
 * Por exemplo: após gerar zip, você poderá fazer upload para um servidor ftp
 * Usa Thread para pemitir rodar o programa em "segundo plano".
 */
public class Compactador extends Thread {

	// tamanho máximo do buffer de leitura
	private final int TAM_BUFFER = 1024;
	 // arquivo ou pasta para zipar
	private String origem;
	// arquivo .zip a ser criado
	private String zipDestino;
	private Label mensagem;

	// Compacta o arquivo ou toda a pasta origem para o arquivo destino
	public Compactador(String origem, String zipDestino, Label mensagem) {
		this.origem = origem;
		this.zipDestino = zipDestino;
		this.mensagem = mensagem;
	}

	@Override
	public void run() {;

		try {
			aviso("Compactando arquivo(s)...");
		
			// número de arquivos compactados
			int total = 0;

			// buffer de entrada representa cada arquivo que será compactado
			BufferedInputStream entrada = null;

			// o zip de saida é gravado em um buffer de saida que é gravado no arquivo destino
			ZipOutputStream zipSaida = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipDestino)));
			
			// os dados são copiados da origem para o vetor dados[] e depois gravados no destino
			byte dados[] = new byte[TAM_BUFFER];

			// lista contendo os nomes de todos os arquivos a serem zipados
			String[] listaArquivos;
				
			// nome da pasta onde estão os arquivos a serem zipados 
			// ou nome de um único arquivo para zipar
			File arquivos = new File(origem);
			
			if (arquivos.isFile()){
				// lista contendo o nome do único arquivo a ser zipado
				listaArquivos = new String[1];
				listaArquivos[0] = arquivos.getName();
				origem = arquivos.getParent() + "/";  // pasta contendo o arquivo a ser zipado
				arquivos = new File(origem);				
			} else {
				listaArquivos = arquivos.list();
			}
			
			String arqOrigem = null;

			// para cada arquivo da lista...
			for (int i = 0; i < listaArquivos.length; i++) {

				// inclui o caminho do arquivo: Ex.: "d:\\temp\\" + "arquivo1.txt"
				arqOrigem = origem + listaArquivos[i];

				// não considera o arquivoDestino, caso já exista
				if (!arqOrigem.equalsIgnoreCase(zipDestino)) {
					File arq = new File(arqOrigem);

					// não compacta subdiretórios
					if (arq.isFile()) {
						total++;
						aviso("Compactando: " + arqOrigem);
						
						// cria um buffer de leitura para cada arquivo a ser zipado
						entrada = new BufferedInputStream(new FileInputStream(arqOrigem), TAM_BUFFER);

						// cria uma entrada (nome do arquivo a ser gravado, sem o caminho) dentro do arquivo zip
						zipSaida.putNextEntry(new ZipEntry(listaArquivos[i]));

						// quantidade de bytes lidos do arquivo de origem
						int tamanho;

						// enquanto a quantidade de bytes lidos do arquivo de origem > 0 continua lendo
						while ((tamanho = entrada.read(dados)) > 0) {
							// grava os dados lidos no zip de saida
							zipSaida.write(dados, 0, tamanho); // 0 = deslocamento dos bytes
							// dorme 10 milisegundos para permitir a troca de processos
							Thread.sleep(10);  
						}
						entrada.close();
					}
				}
			}

			// Fim do trabalho: fecha arquivo zip esvaziando o buffer de saida (zipSaida)
			zipSaida.close();
			aviso(total + " arquivo(s) compactado(s)");
			
		} catch (IOException e) {
			e.printStackTrace();
			aviso("Erro de compactação: " + e.getMessage());
			
		} catch (InterruptedException e) {
			e.printStackTrace();
			aviso("Erro de compactação: " + e.getMessage());
		}
	}
	
	private void aviso(String msg){
		if (mensagem != null)
		   mensagem.setText(msg);
		else
			System.out.println(msg);
	}
}
