package com.greinet.tvtotalripper.download;

import com.greinet.tvtotalripper.crawler.CrawlerUtil;
import com.greinet.tvtotalripper.crawler.EpisodeWrapper;
import com.greinet.tvtotalripper.ui.SettingsRipperPanel;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.swing.SwingWorker;

/**
 * A task representing a single file download
 */
public class DownloadTask extends SwingWorker<Void, Void> {
    
    /** The download buffer size */
    private static final int BUFFER_SIZE = 4096;
    /** The episode of the downloaded file */
    private final EpisodeWrapper episodeWrapper;
    
    /**
     * Create a download task for a episode
     * @param episodeWrapper 
     */
    public DownloadTask(EpisodeWrapper episodeWrapper) {
        this.episodeWrapper = episodeWrapper;
    }

    /**
     * Get the episode of the download
     * @return the episode
     */
    public EpisodeWrapper getEpisodeWrapper() {
        return episodeWrapper;
    }

    @Override
    public String toString() {
        return episodeWrapper.getTitle()+" : " + getState();
    }
    
    /** The bytes size of the file to download */
    private long fileSize = 0;
    
    /** the amount of downloaded bytes */
    private long totalBytesRead = 0;
    
    /** The completion percentage */
    private int percentCompleted = 0;
    
    /**
     * Executed in background thread
     */
    @Override
    protected Void doInBackground() throws Exception {
        try {
            String downloadURL = CrawlerUtil.getFetchfileURL(episodeWrapper.getUrl());
            
            ConnectionUtil util = new ConnectionUtil();
            util.prepare(downloadURL);
            fileSize = util.getContentLength();
             
            InputStream inputStream = util.getInputStream();
            
            String fixedTitle = episodeWrapper.getTitle().replace(":", " ");
            
            File outputShowFolder = new File(SettingsRipperPanel.DOWNLOADFOLDER, episodeWrapper.getShow());
            if(!outputShowFolder.exists()){
                outputShowFolder.mkdir();
            }
            File outputSeasonFolder = new File(outputShowFolder, episodeWrapper.getSeason());
            if(!outputSeasonFolder.exists()){
                outputSeasonFolder.mkdir();
            }
            File outputFile = new File(outputSeasonFolder, fixedTitle+".mp4");
            if(outputFile.exists()){
                if(outputFile.length() == fileSize){
                    done();
                    return null;
                }else{
                    outputFile.delete();
                }
            }
            try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
                byte[] buffer = new byte[BUFFER_SIZE];
                int bytesRead;
                totalBytesRead = 0;
                percentCompleted = 0;
                int oldPercentCompleted = 0;
                

                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                    totalBytesRead += bytesRead;
                    percentCompleted = (int) (totalBytesRead * 100 / fileSize);
                    firePropertyChange(Long.toString(episodeWrapper.getId()), oldPercentCompleted, percentCompleted);
                    oldPercentCompleted = percentCompleted;
                }
            }
            util.disconnect();

            // Enable MetaDataWriter
            // MetaDataWriter mdp = new MetaDataWriter();
            // mdp.writeMetadata(outputFile.getAbsolutePath(), episodeWrapper.getTitle(), episodeWrapper.getShow(), episodeWrapper.getShow(), episodeWrapper.getEpisode());
            
        } catch (IOException ex) {
            cancel(true);          
        }
        return null;
    }

    /**
     * Get the download file size in bytes
     * @return the file size in bytes
     */
    public long getFileSize() {
        return fileSize;
    }

    /** 
     * Get the amount of already downloaded bytes
     * @return the amount of already downloaded bytes  
     */
    public long getTotalBytesRead() {
        return totalBytesRead;
    }

    /**
     * Get the completiton percentage
     * @return the completition percentage
     */
    public int getPercentCompleted() {
        return percentCompleted;
    }

    /**
     * Fire a property change event with the progress value of 101 meaning that the task is done
     */
    @Override
    protected void done() {
        firePropertyChange(Long.toString(episodeWrapper.getId()), 0, 101);
    }  
}
