package lighthouse.subwindows;

import com.google.common.collect.ImmutableList;
import com.google.protobuf.Message;
import javafx.application.Platform;
import lighthouse.Main;
import lighthouse.files.DiskManager;
import lighthouse.protocol.Project;
import lighthouse.utils.GuiUtils;
import lighthouse.wallet.PledgingWallet;
import de.jensd.fx.fontawesome.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.input.*;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.FileChooser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;

public class ExportWindow {
    private static final Logger log = LoggerFactory.getLogger(ExportWindow.class);

    @FXML StackPane dragArea;
    @FXML Label moneyIcon;

    public Main.OverlayUI<InnerWindow> overlayUI;

    private Project project;
    @Nullable private PledgingWallet.PendingPledge pledge;

    public void initialize() {
        // TODO: Make a composite icon that looks more pledgey.
        AwesomeDude.setIcon(moneyIcon, AwesomeIcon.MONEY, "70.0");
        moneyIcon.setTextFill(Color.valueOf("#cccccc"));
    }

    public static void openForPledge(Project project, PledgingWallet.PendingPledge pledge) {
        log.info("Open ExportWindow for a pledge for {}", project.getTitle());
        ExportWindow window = Main.instance.<ExportWindow>overlayUI("subwindows/export.fxml", "Export pledge").controller;
        window.project = project;
        window.pledge = pledge;
    }

    public static void openForProject(Project project) {
        log.info("Open ExportWindow for saving project '{}'", project.getTitle());
        ExportWindow window = Main.instance.<ExportWindow>overlayUI("subwindows/export.fxml", "Export project").controller;
        window.project = project;
    }

    public static DataFormat PLEDGE_MIME_TYPE = new DataFormat("application/vnd.vinumeris.lighthouse-pledge");
    public static DataFormat PROJECT_MIME_TYPE = new DataFormat("application/vnd.vinumeris.lighthouse-crowdfund");

    public static class DragData {
        public Path tempDragDirectory, tempDragFile;

        public void done() {
            log.info("Drag done!");
            // Tell the JVM to clean up at shutdown time. If we delete too early the OS notifies the drag is done but
            // the file manager is still trying to grab the file. There doesn't seem to be any way to provide a named
            // file for dragging without it already being on the filesystem.
            Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                try {
                    log.info("Deleting temp file+dir {}", tempDragFile);
                    Files.delete(tempDragFile);
                    Files.delete(tempDragDirectory);
                } catch (IOException e) {
                    log.error("Could not delete temp dir after drag", e);
                }
            }, "Temp file deleter thread"));
        }
    }

    private DragData dragData;

    @FXML
    public void dragDetected(MouseEvent event) {
        // Create a temp directory so the file can have a nice name, and then we will delete it a few seconds
        // after the drag operation has finished.
        final String fileName = getFileName();
        boolean savingPledge = pledge != null;
        Message data = savingPledge ? pledge.getData() : project.getProto();
        final DataFormat mimeType = savingPledge ? PLEDGE_MIME_TYPE : PROJECT_MIME_TYPE;
        dragData = startDrag(fileName, data, mimeType, dragArea);
    }

    public static DragData startDrag(String fileName, Message data, DataFormat mimeType, Node dragArea) {
        try {
            DragData dd = new DragData();
            dd.tempDragDirectory = Files.createTempDirectory(Main.APP_NAME);
            dd.tempDragFile = dd.tempDragDirectory.resolve(fileName);
            try (OutputStream outputStream = Files.newOutputStream(dd.tempDragFile)) {
                data.writeTo(outputStream);
            }
            Dragboard dragboard = dragArea.startDragAndDrop(TransferMode.COPY);
            ClipboardContent content = new ClipboardContent();
            content.putFilesByPath(ImmutableList.of(dd.tempDragFile.toString()));
            content.put(mimeType, data.toByteArray());
            dragboard.setContent(content);
            return dd;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private String getFileName() {
        // TODO: Sanitize the project name for files.
        if (pledge != null) {
            final String FILE_NAME = "Pledge by %s for %s%s";
            return String.format(FILE_NAME, System.getProperty("user.name"), project.getTitle(), DiskManager.PLEDGE_FILE_EXTENSION);
        } else {
            return project.getSuggestedFileName();
        }
    }

    @FXML
    public void dragDone(DragEvent event) {
        dragData.done();
        if (pledge != null)
            pledge.commit(true);
        overlayUI.done();
    }

    @FXML
    public void saveClicked() {
        // runLater: shitty hack around RT-37821 (consider upgrading to 8u40 when available and/or applying fix locally)
        // otherwise pressing enter can cause a crash here when we open a new window with a default button
        Platform.runLater(() -> {
            boolean savingPledge = pledge != null;
            log.info("Save clicked for {}", savingPledge ? "pledge" : "project");

            FileChooser chooser = new FileChooser();
            chooser.setTitle(savingPledge ? "Save pledge to a file" : "Save project to a file");
            chooser.setInitialFileName(getFileName());
            GuiUtils.platformFiddleChooser(chooser);
            File file = chooser.showSaveDialog(Main.instance.mainStage);
            if (file == null) {
                log.info(" ... but user cancelled");
                return;
            }
            Message data = savingPledge ? pledge.getData() : project.getProto();
            log.info("Saving {} data to {}", pledge != null ? "pledge" : "project", file);
            try (OutputStream outputStream = new FileOutputStream(file)) {
                data.writeTo(outputStream);
                if (pledge != null)
                    pledge.commit(true);
                overlayUI.done();   // Only if successful.
            } catch (IOException e) {
                GuiUtils.informationalAlert("Failed to save file", e.getLocalizedMessage());
            }
        });
    }

    @FXML
    public void closeWidgetClicked(MouseEvent event) {
        overlayUI.done();
    }
}

@@ -4948,16 +4948,40 @@
 LE_NAME,
+ Main.demoName == null ?
  System.
@@ -5004,16 +5004,32 @@
 r.name%22)
+ : Main.demoName
 , projec

Use demo name in pledge files if set.