/*
    Copyright (c) 2005-2013 Leisenfels. All rights reserved.
    Use is subject to license terms.
*/

package com.lf.vfslib.test.dropbox;

import com.dropbox.core.DbxAppInfo;
import com.dropbox.core.DbxAuthFinish;
import com.dropbox.core.DbxRequestConfig;
import com.dropbox.core.DbxWebAuthNoRedirect;
import com.lf.commons.i18n.Locale;
import com.lf.commons.lang.JavaUtils;
import com.lf.vfslib.VFSLib;
import com.lf.vfslib.core.VFSLibSettings;
import com.lf.vfslib.dropbox.DbxFileProvider;
import com.lf.vfslib.dropbox.DbxFileSystemConfigBuilder;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.FileType;
import org.apache.commons.vfs2.VFS;
import org.apache.commons.vfs2.impl.DefaultFileSystemManager;

import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;


/**
 * Example class showing the use of the Dropbox&reg; provider.
 * <p/>
 * Required libraries in classpath:
 * <code>
 * commons-vfs-2.0.jar          Original Apache VFS 2.0 library
 * commons-logging-1.1.jar      Required for VFS 2.0
 * dropbox-core-sdk-1.7.2.jar   Dropbox&reg; SDK
 * jackson-core-2.2.2.jar       Jackson JSON processor
 * </code>
 * <p/>
 * @author Axel Schwolow
 * @version $Revision: 1.7 $, $Date: 2013/10/10 17:35:47 $
 * @since 1.6
 */
public class ExampleDropbox {


    /**
     * Constructor method.
     * <p/>
     * @param language         The language (en|de)
     * @param licensefile      The license key file
     * @param appkey           The application key from Dropbox&reg;
     * @param appsecret        The application secret from Dropbox&reg;
     * @param clientidentifier The identifier for application
     * @param token            The access token (requires prior authorization)
     * @throws FileSystemException Error indication
     * @since 1.6
     */
    public ExampleDropbox (String language, File licensefile, String appkey, String appsecret,
                           String clientidentifier, String token) throws FileSystemException {

        System.out.println("Configuring VFSLib Dropbox provider:");
        System.out.println("    language           " + (language != null ? language : "(using English)"));
        System.out.println("    licensefile        " + licensefile);
        System.out.println("    appkey             " + appkey);
        System.out.println("    appsecret          " + appsecret);
        System.out.println("    clientidentifier   " + (clientidentifier != null ? clientidentifier : "(using default)"));
        System.out.println("    token              " + (token != null ? token.replaceFirst("^.{5}", "*****") : "(please authorize first)"));

        // Messages from VFSLib should be printed in the user's language (optional, default is "eng_US").
        // VFSLib supports ISO 639-2 codes (three language letters) which allows languages like "nds" (Low German).
        VFSLibSettings settings = VFSLibSettings.getSharedInstance();
        if (language == null) language = "en";
        if (!language.equals("en")) {
            settings.setUserLocale(Locale.parseLocale(language));  // Maps "de" -> "ger_DE"
        }
        if (clientidentifier == null) clientidentifier = "VFSLib/" + settings.getDeployProps().getVersion();

        // Setup the main VFSLib instance, get evaluation license key from Leisenfels website
        VFSLib vfslib = new VFSLib();
        if (licensefile == null) {
            JFileChooser chooser = new JFileChooser("Please choose a VFSLib license file");
            chooser.setFileFilter(new FileNameExtensionFilter("License Files", "txt"));
            chooser.showOpenDialog(null);
            licensefile = chooser.getSelectedFile();
            System.out.println("The VFSLib license file is: " + licensefile);
        }
        vfslib.setLicenseFile(licensefile);          // Import from file

        // We use the default file system manager here
        DefaultFileSystemManager fsmanager = (DefaultFileSystemManager) VFS.getManager();

        // Add Dropbox provider to VFS, ask user for missing arguments
        if (appkey == null) {
            appkey = JOptionPane.showInputDialog("Please enter the application key from Dropbox");
            System.out.println("The Dropbox application key is: " + appkey);
        }
        if (appsecret == null) {
            appsecret = JOptionPane.showInputDialog("Please enter the application secret from Dropbox");
            System.out.println("The Dropbox application secret is: " + appsecret);
        }
        DbxFileProvider provider = vfslib.addProviderDropbox(fsmanager, appkey, appsecret, clientidentifier, language);
        if (provider == null) {
            System.err.println("Sorry, the Dropbox provider could not be activated, exiting");
            return;
        }

        String scheme = vfslib.getSchemeDropbox();
        System.out.println("\nAdded Dropbox scheme \"" + scheme + '\"');

        if (token == null) {
            // Perform authorization to let application access a Dropbox account
            DbxAppInfo appinfo = provider.getAppInfo();
            DbxRequestConfig reqconfig = provider.getRequestConfig();

            // Open connection to Dropbox and get authorization URL to direct the user to
            DbxWebAuthNoRedirect webAuth = new DbxWebAuthNoRedirect(reqconfig, appinfo);
            final String authorizeurl = webAuth.start();
            if (authorizeurl == null) {
                System.err.println("Sorry, could not connect to dropbox.com, exiting");
                return;
            }

            // Open default web browser showing the received web address
            new Thread(new Runnable() {
                @Override
                public void run () {
                    try { Thread.sleep(3000); }
                    catch (Exception e) { }
                    JavaUtils.browse(authorizeurl);
                }
            }).start();
            System.out.println("If your browser did not open the Dropbox website, please go to " + authorizeurl);

            String code = JOptionPane.showInputDialog("Please enter the code from Dropbox (please wait for browser)");
            System.out.println("The Dropbox code is: " + code);

            // Get final access token, could be stored permanently e.g. in database
            try {
                DbxAuthFinish authfinish = webAuth.finish(code);
                token = authfinish.accessToken;
            }
            catch (Exception e) { }
            if (token == null) {
                System.err.println("Sorry, could not get the Dropbox access token, exiting");
                return;
            }
            System.out.println("The Dropbox access token is: " + token);
            System.out.println("You can use this token for further testing, please specify as -token command line argument now");
        }

        // Pass access token over to VFSLib to access the Dropbox account
        FileSystemOptions options = new FileSystemOptions();
        DbxFileSystemConfigBuilder builder = new DbxFileSystemConfigBuilder();
        builder.setAccessToken(options, token);
        builder.setChunkSize(options, 4096);  // Allow data portions being transferred

        // Setup proper account name, used as user name for Dropbox URLs (failsafe is "anonymous"):
        //    dropbox://[name]:[token]@dropbox.com
        String username = "johndoe";
        builder.setAccountDisplayName(options, username);


        // List a Dropbox folder
        String uri = scheme + "://" + username + "@dropbox.com";
        System.out.println("Listing child entries of " + uri + ":");
        try {
            FileObject fileobj = fsmanager.resolveFile(uri, options);
            if (fileobj.getType().equals(FileType.FOLDER)) {
                FileObject[] childs = fileobj.getChildren();
                for (FileObject next : childs) {
                    if (next.getType().equals(FileType.FOLDER)) {
                        System.out.println("    DIR:  " + String.valueOf(next));
                    }
                    else System.out.println("    FILE: " + String.valueOf(next));
                }
            }
            else System.out.println("    Entry " + uri + " is not a folder");
        }
        catch (Exception e) { e.printStackTrace(); }

        // The following code modifies files in the Dropbox file system.
        // Please uncomment the lines and adjust values for your needs.

        // Create a Dropbox folder
        String tempfolder = scheme + "://" + username + "@dropbox.com/0123456789abcdefghijklmnopqrstuvwxyz";
        System.out.println("Creating temporary folder " + tempfolder + ":");
        boolean success = false;
        try {
            FileObject fileobj = fsmanager.resolveFile(tempfolder, options);
            if (!fileobj.exists()) {
                fileobj.createFolder();
                success = fileobj.exists();
                System.out.println(success ? "    Successful" : "    Failed");
            }
            else {
                System.out.println("    Entry " + tempfolder + " does already exist, exiting");
                return;
            }
        }
        catch (Exception e) { e.printStackTrace(); }
        if (!success) {
            System.err.println("Sorry, could not create folder, exiting");
            return;
        }

        String content = "Hello world!";
        String encoding = "ISO-8859-1";

        // Upload a file to Dropbox. Get file type, last modified, and size.
        String tempfile = tempfolder + "/readme.txt";
        System.out.println("Uploading temporary file " + tempfile + ":");
        success = false;
        try {
            FileObject fileobj = fsmanager.resolveFile(tempfile, options);
            OutputStream ostream = fileobj.getContent().getOutputStream();
            ostream.write(content.getBytes(encoding));
            ostream.flush();
            ostream.close();

            success = fileobj.exists();
            System.out.println(success ? "    Successful" : "    Failed");

            System.out.println("    TYPE:  " + fileobj.getType().getName());
            System.out.println("    MOD:   " + new Date(fileobj.getContent().getLastModifiedTime()));  // Currently not supported for folders
            System.out.println("    SIZE:  " + fileobj.getContent().getSize());
        }
        catch (Exception e) { e.printStackTrace(); }
        if (!success) {
            System.err.println("Sorry, could not upload file, exiting");
            return;
        }

        // Rename a Dropbox file
        String tempfilerenamed = tempfolder + "/README";  // README.TXT not possible currently
        System.out.println("Renaming temporary file " + tempfile + " to " + tempfilerenamed + ":");
        success = false;
        try {
            FileObject fileobj = fsmanager.resolveFile(tempfile, options);
            FileObject fileobjrenamed = fsmanager.resolveFile(tempfilerenamed, options);
            fileobj.moveTo(fileobjrenamed);
            success = fileobjrenamed.exists();
            System.out.println(success ? "    Successful" : "    Failed");
            if (success) tempfile = tempfilerenamed;
        }
        catch (Exception e) { e.printStackTrace(); }
        if (!success) {
            System.err.println("Sorry, could not rename file, exiting");
            return;
        }

        // Download a file from Dropbox
        System.out.println("Downloading temporary file " + tempfile + ":");
        success = false;
        try {
            FileObject fileobj = fsmanager.resolveFile(tempfile, options);
            ByteArrayOutputStream bostream = new ByteArrayOutputStream();
            InputStream istream = fileobj.getContent().getInputStream();
            int len;
            byte[] buffer = new byte[1024];
            while ((len = istream.read(buffer)) != -1) {
                bostream.write(buffer, 0, len);
            }
            istream.close();
            bostream.flush();
            bostream.close();
            String loaded = new String(bostream.toByteArray(), encoding);

            success = loaded.equals(content);
            System.out.println(success ? "    Successful (content=" + loaded + ")" : "    Failed");
        }
        catch (Exception e) { e.printStackTrace(); }
        if (!success) {
            System.err.println("Sorry, could not download file, exiting");
            return;
        }

        // Remove a Dropbox file and folder
        System.out.println("Removing temporary entries:");
        success = false;
        try {
            // Remove file
            FileObject fileobj = fsmanager.resolveFile(tempfile, options);
            System.out.print("    " + tempfile);
            success = fileobj.delete();
            System.out.println(success ? "  Successful" : "    Failed");

            // Remove folder
            fileobj = fsmanager.resolveFile(tempfolder, options);
            System.out.print("    " + tempfolder);
            success = fileobj.delete();
            System.out.println(success ? "  Successful" : "    Failed");
        }
        catch (Exception e) { e.printStackTrace(); }
        if (!success) {
            System.err.println("Sorry, could not remove file/folder, exiting");
            return;
        }
    }

    /**
     * Functionality for testing and debugging.
     * <p/>
     * Supported arguments:
     * <code>
     * -language [value]           Language "en" or "de"
     * -licensefile [file]         License file
     * -appkey [value]             Your application key from Dropbox&reg;
     * -appsecret [value]          Your application secret from Dropbox&reg;
     * -clientidentifier [value]   The identifier for your application
     * -token [value]              The access token (requires prior authorization)
     * </code>
     * <p/>
     * @param args Array of strings with console arguments
     * @since 1.6
     */
    public static void main (String[] args) {

        String language = null, appkey = null, appsecret = null, clientidentifier = null, token = null;
        File licensefile = null;

        try {
            if (GraphicsEnvironment.isHeadless()) {
                System.err.println("\nSorry, this example requires a graphical environment, exiting");
                System.exit(1);
            }

            // Disable annoying VFS log messages like:
            // 20.09.2013 13:48:31 org.apache.commons.vfs2.VfsLog info
            // INFO: Using "C:\DOCUME~1\User1\LOCALS~1\Temp\vfs_cache" as temporary files store.
            System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.NoOpLog");
            System.out.println("");

            // Parse arguments
            for (int i = 0; i < args.length; i++) {
                if (args[i].equals("-language") && (i + 1) < args.length) language = args[++i];
                else if (args[i].equals("-licensefile") && (i + 1) < args.length) licensefile = new File(args[++i]);
                else if (args[i].equals("-appkey") && (i + 1) < args.length) appkey = args[++i];
                else if (args[i].equals("-appsecret") && (i + 1) < args.length) appsecret = args[++i];
                else if (args[i].equals("-clientidentifier") && (i + 1) < args.length) clientidentifier = args[++i];
                else if (args[i].equals("-token") && (i + 1) < args.length) token = args[++i];
            }

            new ExampleDropbox(language, licensefile, appkey, appsecret, clientidentifier, token);
            System.exit(0);
        }
        catch (Exception exc) {
            try { Thread.sleep(1000); }
            catch (Exception e) { }
            exc.printStackTrace();
        }
        System.exit(1);
    }
}
