package vandy.mooc.common;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;

import vandy.mooc.R;
import android.content.Context;
import android.net.Uri;
import android.util.Base64;
import android.util.Log;

/**
 * @class DownloadUtils
 *
 * @brief This class encapsulates several static methods so that all
 *        Services can access them without redefining them in each
 *        Service.
 */
public class DownloadUtils {
    /**
     * Used for debugging.
     */
    static final String TAG = 
        DownloadUtils.class.getSimpleName();
    
    /**
    * If you have access to a stable Internet connection for testing
    * purposes, feel free to change this variable to false so it
    * actually downloads the image from a remote server.
    */
    static final boolean DOWNLOAD_OFFLINE = false;
    
    /**
     * The resource that we write to the file system in offline
     * mode. Note that this must be the same image that the testing
     * project expects. (found in res/drawable-nodpi and Options.java)
     */
    static final int OFFLINE_TEST_IMAGE = R.raw.dougs;
	
    /**
     * The file name that we should use to store the image in offline mode
     */
    static final String OFFLINE_FILENAME = "dougs.jpg";
    
    /**
     * Download the file located at the provided internet url using
     * the URL class, store it on the android file system using
     * openFileOutput(), and return the path to the file on disk.
     *
     * @param context	the context in which to write the file
     * @param uri       the web url
     * 
     * @return          the path to the downloaded file on the file system
     */
    public static Uri downloadFile(Context context,
                                   Uri uri) {
        // If we're offline, write the image in our resources to disk,
        // then return that pathname.
        if (DOWNLOAD_OFFLINE) {
            // Store the image on the file system. We can store it as
            // private since the test project runs in the same process
            // as the target project.
            try (FileOutputStream out =
                     context.openFileOutput(OFFLINE_FILENAME, 0);
                 InputStream in =
                 context.getResources().openRawResource(OFFLINE_TEST_IMAGE)) {
                 // Write the resource to disk.
                copy(in, 
                     out);
            } catch (Exception e) {
                Log.e(TAG,
                      "Exception while downloading. Returning null.");
                Log.e(TAG,
                      e.toString());
                e.printStackTrace();
                return null;
            }
            return Uri.parse(context.getFilesDir().toString() 
                             + File.separator 
                             + OFFLINE_FILENAME);
        }
        // Otherwise, go ahead and download the file
        else {
            // Create a temp file.
            final File file = getTemporaryFile(context,
                                               uri.toString());
            Log.d(TAG,
                  "    downloading to " 
                  + file);
	
            // Download the contents at the URL, which should
            // reference an image.
            try (final InputStream in = (InputStream)
                     new URL(uri.toString()).getContent();
                 final OutputStream os =
                     new FileOutputStream(file)) {
                 // Copy the contents of the downloaded image to the
                 // temp file.
                 copy(in, 
                      os);
            } catch (Exception e) {
                Log.e(TAG,
                      "Exception while downloading. Returning null.");
                Log.e(TAG,
                      e.toString());
                e.printStackTrace();
                return null;
            }

            // Return the pathname of the temp file.
            return Uri.parse(file.getAbsolutePath());
        }
    }
        
    /**
     * Create a temp file to store the result of a download.
     * 
     * @param context
     * @param url
     * @return
     * @throws IOException
     */
    static private File getTemporaryFile(Context context,
                                         String url) {
        // This is what you'd normally call to get a unique temporary
        // file, but for testing purposes we always name the file the
        // same to avoid filling up student phones with numerous
        // files!
        // return context.getFileStreamPath(Base64.encodeToString(url.getBytes(),
        //                                  Base64.NO_WRAP)
        //                                  + System.currentTimeMillis());
        return context.getFileStreamPath(Base64.encodeToString(url.getBytes(),
                                                               Base64.NO_WRAP));
    }

    /**
     * Copy the contents of an InputStream into an OutputStream.
     * 
     * @param in
     * @param out
     * @return
     * @throws IOException
     */
    static public int copy(final InputStream in,
                           final OutputStream out) throws IOException {
        final int BUFFER_LENGTH = 1024;
        final byte[] buffer = new byte[BUFFER_LENGTH];
        int totalRead = 0;
        int read = 0;

        while ((read = in.read(buffer)) != -1) {
            out.write(buffer, 0, read);
            totalRead += read;			
        }

        return totalRead;
    }
}
