// ============================================================================
//
// Copyright (C) 2006-2019 Talend Inc. - www.talend.com
//
// This source code is available under agreement available at
// %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
//
// You should have received a copy of the agreement
// along with this program; if not, write to Talend SA
// 9 rue Pages 92150 Suresnes, France
//
// ============================================================================
package org.talend.camel.designer.ui.wizards;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.util.BidiUtils;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.internal.wizards.datatransfer.DataTransferMessages;
import org.talend.camel.core.model.camelProperties.CamelProcessItem;
import org.talend.camel.designer.i18n.Messages;
import org.talend.camel.designer.ui.wizards.actions.JavaCamelJobScriptsExportWSAction;
import org.talend.camel.designer.ui.wizards.actions.JavaCamelJobScriptsExportWithMavenAction;
import org.talend.commons.ui.runtime.exception.MessageBoxExceptionHandler;
import org.talend.commons.utils.io.FilesUtils;
import org.talend.core.PluginChecker;
import org.talend.core.model.properties.ProcessItem;
import org.talend.core.repository.constants.FileConstants;
import org.talend.core.runtime.process.IBuildJobHandler;
import org.talend.core.runtime.process.TalendProcessArgumentConstant;
import org.talend.core.runtime.repository.build.IBuildResourceParametes;
import org.talend.designer.maven.tools.AggregatorPomsHelper;
import org.talend.designer.maven.utils.PomIdsHelper;
import org.talend.designer.maven.utils.PomUtil;
import org.talend.designer.runprocess.IProcessor;
import org.talend.designer.runprocess.ProcessorUtilities;
import org.talend.repository.model.RepositoryNode;
import org.talend.repository.ui.wizards.exportjob.ExportTreeViewer;
import org.talend.repository.ui.wizards.exportjob.JavaJobScriptsExportWSWizardPage;
import org.talend.repository.ui.wizards.exportjob.JavaJobScriptsExportWSWizardPage.JobExportType;
import org.talend.repository.ui.wizards.exportjob.JavaJobScriptsExportWizardPage;
import org.talend.repository.ui.wizards.exportjob.JobScriptsExportWizardPage;
import org.talend.repository.ui.wizards.exportjob.scriptsmanager.BuildJobFactory;
import org.talend.repository.ui.wizards.exportjob.scriptsmanager.JobScriptsManager;
import org.talend.repository.ui.wizards.exportjob.scriptsmanager.JobScriptsManager.ExportChoice;
import org.talend.repository.ui.wizards.exportjob.scriptsmanager.JobScriptsManagerFactory;
import org.talend.repository.ui.wizards.exportjob.util.ExportJobUtil;

/**
 * DOC x class global comment. Detailled comment <br/>
 *
 */
public class JavaCamelJobScriptsExportWSWizardPage extends JobScriptsExportWizardPage {

    private static final String EXPORTTYPE_KAR = Messages.getString("JavaCamelJobScriptsExportWSWizardPage.ExportKar");//$NON-NLS-1$

    private static final String EXPORTTYPE_SPRING_BOOT = Messages
            .getString("JavaCamelJobScriptsExportWSWizardPage.ExportSpringBoot");//$NON-NLS-1$

    private static final String EXPORTTYPE_SPRING_BOOT_DOCKER_IMAGE = Messages
            .getString("JavaCamelJobScriptsExportWSWizardPage.ExportSpringBootDockerImage");//$NON-NLS-1$

    // dialog store id constants
    private static final String STORE_DESTINATION_NAMES_ID = "JavaJobScriptsExportWizardPage.STORE_DESTINATION_NAMES_ID"; //$NON-NLS-1$

    private boolean onlyExportDefaultContext;

    private boolean exportAsZip;

    private boolean addMavenScript;

    protected Button exportAsZipButton;

    protected Combo exportTypeCombo;

    protected Composite pageComposite;

    protected Composite optionsGroupComposite;

    protected Composite optionsDockerGroupComposite;

    protected GridData optionsGroupCompositeLayout;

    protected Composite destinationNameFieldComposite;

    protected Composite destinationNameFieldInnerComposite;

    private Label destinationLabel;

    private Combo destinationNameField;

    private Button destinationBrowseButton;

    public JavaCamelJobScriptsExportWSWizardPage(IStructuredSelection selection) {
        super("JavaCamelJobScriptsExportWSWizardPage", selection);
    }

    @Override
    protected void createUnzipOptionGroup(Composite parent) {
        // options group
        Group optionsGroup = new Group(parent, SWT.NONE);
        GridLayout layout = new GridLayout();
        optionsGroup.setLayout(layout);
        optionsGroup.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL));
        optionsGroup.setText(Messages.getString("JavaJobScriptsExportWSWizardPage.BuildType")); //$NON-NLS-1$
        optionsGroup.setFont(parent.getFont());

        optionsGroup.setLayout(new GridLayout(2, false));

        Label label = new Label(optionsGroup, SWT.NONE);
        label.setText(Messages.getString("JavaJobScriptsExportWSWizardPage.BuildLabel")); //$NON-NLS-1$

        boolean canESBMicroServiceDockerImage = PluginChecker.isDockerPluginLoaded();

        exportTypeCombo = new Combo(optionsGroup, SWT.PUSH);

        // TESB-5328
        exportTypeCombo.add(EXPORTTYPE_KAR);
        if (PluginChecker.isTIS()) {
            exportTypeCombo.add(EXPORTTYPE_SPRING_BOOT);

            if (canESBMicroServiceDockerImage) {
                exportTypeCombo.add(EXPORTTYPE_SPRING_BOOT_DOCKER_IMAGE);
            }
        }
        // exportTypeCombo.setEnabled(false); // only can export kar file
        exportTypeCombo.setText(EXPORTTYPE_KAR);

        exportTypeCombo.addSelectionListener(new SelectionAdapter() {

            /*
             * (non-Javadoc)
             *
             * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
             */
            @Override
            public void widgetSelected(SelectionEvent e) {
                Widget source = e.widget;
                if (source instanceof Combo) {
                    String destination = ((Combo) source).getText();
                    boolean isMS = destination.equals(EXPORTTYPE_SPRING_BOOT)
                            || destination.equals(EXPORTTYPE_SPRING_BOOT_DOCKER_IMAGE);

                    if (isMS) {
                        contextButton.dispose();
                        addBSButton.dispose();
                        exportAsZipButton.dispose();

                        optionsDockerGroupComposite.dispose();

                        if (destination.equals(EXPORTTYPE_SPRING_BOOT)) {
                            updateDestinationGroup(false);
                            createOptionsForKar(optionsGroupComposite, optionsGroupFont);
                            optionsGroupComposite.layout(true, true);
                        } else {
                            updateDestinationGroup(true);
                            createOptionsForDocker(optionsGroupComposite, optionsGroupFont);
                            createDockerOptions(parent);
                            restoreWidgetValuesForImage();
                            optionsGroupComposite.layout(true, true);
                        }

                        parent.layout();

                    } else {
                        if(contextButton != null) contextButton.setEnabled(false);
                        if(exportAsZipButton != null) exportAsZipButton.setEnabled(false);
                    }

                    String destinationValue = getDestinationValue();

                    if (isMS) {
                        if (exportAsZip) {
                            destinationValue = destinationValue.substring(0, destinationValue.lastIndexOf("."))
                                    + FileConstants.ZIP_FILE_SUFFIX;
                        } else {
                            destinationValue = destinationValue.substring(0, destinationValue.lastIndexOf("."))
                                    + FileConstants.JAR_FILE_SUFFIX;
                        }
                    } else {
                        destinationValue = destinationValue.substring(0, destinationValue.lastIndexOf(".")) + getOutputSuffix();
                    }

                    setDestinationValue(destinationValue);
                }

            }
        });
    }

    protected void updateDestinationGroup(boolean isImage) {
        destinationLabel.setEnabled(!isImage);
        destinationBrowseButton.setEnabled(!isImage);
        destinationNameField.setEnabled(!isImage);
    }

    private Button localRadio, remoteRadio;

    private Text hostText, imageText, tagText;

    private Label hostLabel, imageLabel, tagLabel;

    private Font optionsGroupFont;

    private void createDockerOptions(Composite parent) {

        optionsDockerGroupComposite = new Composite(parent, SWT.NONE);
        GridDataFactory.fillDefaults().grab(true, false).applyTo(optionsDockerGroupComposite);

        GridLayout gdlOptionsGroupComposite = new GridLayout();
        gdlOptionsGroupComposite.marginHeight = 0;
        gdlOptionsGroupComposite.marginWidth = 0;
        optionsDockerGroupComposite.setLayout(gdlOptionsGroupComposite);

        Group optionsGroup = new Group(optionsDockerGroupComposite, SWT.NONE);
        GridDataFactory.fillDefaults().grab(true, false).applyTo(optionsGroup);

        optionsGroup
                .setText(org.talend.repository.i18n.Messages.getString("JavaJobScriptsExportWSWizardPage.DOCKER.optionGroup")); //$NON-NLS-1$
        optionsGroup.setFont(optionsDockerGroupComposite.getFont());
        optionsGroup.setLayout(new GridLayout());

        Composite dockeOptionsComposite = new Composite(optionsGroup, SWT.NONE);
        GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(dockeOptionsComposite);
        GridLayout dockerOptionsLayout = new GridLayout(3, false);
        dockerOptionsLayout.marginHeight = 0;
        dockerOptionsLayout.marginWidth = 0;
        dockeOptionsComposite.setLayout(dockerOptionsLayout);

        hostLabel = new Label(dockeOptionsComposite, SWT.NONE);
        hostLabel.setText(org.talend.repository.i18n.Messages.getString("JavaJobScriptsExportWSWizardPage.DOCKER.dockerHost")); //$NON-NLS-1$
        Composite hostComposite = new Composite(dockeOptionsComposite, SWT.NONE);
        hostComposite.setLayout(new GridLayout(2, false));

        localRadio = new Button(hostComposite, SWT.RADIO);
        localRadio.setText(org.talend.repository.i18n.Messages.getString("JavaJobScriptsExportWSWizardPage.DOCKER.localHost")); //$NON-NLS-1$
        remoteRadio = new Button(hostComposite, SWT.RADIO);
        remoteRadio.setText(org.talend.repository.i18n.Messages.getString("JavaJobScriptsExportWSWizardPage.DOCKER.remoteHost")); //$NON-NLS-1$
        hostText = new Text(dockeOptionsComposite, SWT.BORDER);
        GridData hostData = new GridData(GridData.FILL_HORIZONTAL);
        hostText.setLayoutData(hostData);

        imageLabel = new Label(dockeOptionsComposite, SWT.NONE);
        imageLabel.setText(org.talend.repository.i18n.Messages.getString("JavaJobScriptsExportWSWizardPage.DOCKER.imageLabel")); //$NON-NLS-1$
        imageText = new Text(dockeOptionsComposite, SWT.BORDER);
        // imageText.setText("${talend.project.name.lowercase}/${talend.job.folder}%a"); //$NON-NLS-1$
        GridDataFactory.fillDefaults().span(2, 1).grab(true, false).applyTo(imageText);

        tagLabel = new Label(dockeOptionsComposite, SWT.NONE);
        tagLabel.setText(org.talend.repository.i18n.Messages.getString("JavaJobScriptsExportWSWizardPage.DOCKER.tagLabel")); //$NON-NLS-1$
        tagText = new Text(dockeOptionsComposite, SWT.BORDER);
        // tagText.setText("${talend.job.version}"); //$NON-NLS-1$
        GridDataFactory.fillDefaults().span(2, 1).grab(true, false).applyTo(tagText);

        updateOptionBySelection();

        // Label additionalLabel = new Label(dockeOptionsComposite, SWT.NONE);
        // additionalLabel.setText("Additional properties");
        // Text additionalText = new Text(dockeOptionsComposite, SWT.BORDER | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL);
        // GridData data = new GridData(GridData.FILL_HORIZONTAL);
        // data.heightHint = 60;
        // additionalText.setLayoutData(data);

        addDockerOptionsListener();

    }

    private String getDefaultImageName(ProcessItem procesItem) {
        IFile pomFile = null;

        if ("ROUTE_MICROSERVICE".equals(
                getProcessItem().getProperty().getAdditionalProperties().get(TalendProcessArgumentConstant.ARG_BUILD_TYPE))) {
            pomFile = AggregatorPomsHelper.getItemPomFolder(procesItem.getProperty()).getFile("pom-microservice.xml");
        } else {
            pomFile = AggregatorPomsHelper.getItemPomFolder(procesItem.getProperty()).getFile("pom-bundle.xml");
        }

        String projectName = PomUtil.getPomProperty(pomFile, "talend.project.name.lowercase"); //$NON-NLS-1$
        String jobFolderPath = PomUtil.getPomProperty(pomFile, "talend.job.folder"); //$NON-NLS-1$
        String jobName = PomUtil.getPomProperty(pomFile, "talend.job.name").toLowerCase(); //$NON-NLS-1$
        return projectName + "/" + jobFolderPath + jobName; //$NON-NLS-1$
    }

    private String getDefaultImageNamePattern() {
        return "${talend.project.name.lowercase}/${talend.job.folder}%a"; //$NON-NLS-1$
    }

    private String getDefaultImageTag(ProcessItem procesItem) {
        return PomIdsHelper.getJobVersion(procesItem.getProperty());
    }

    private String getDefaultImageTagPattern() {
        return "${talend.docker.tag}"; //$NON-NLS-1$
    }

    @Override
    protected void updateOptionBySelection() {
        RepositoryNode[] selectedNodes = treeViewer.getCheckNodes();
        if (selectedNodes.length > 1) {
            imageText.setText(getDefaultImageNamePattern());
            imageText.setEnabled(false);
            tagText.setText(getDefaultImageTagPattern());
            tagText.setEnabled(false);
        } else if (selectedNodes.length == 1) {
            ProcessItem selectedProcessItem = ExportJobUtil.getProcessItem(Arrays.asList(selectedNodes));
            imageText.setText(getDefaultImageName(selectedProcessItem));
            imageText.setEnabled(true);
            tagText.setText(getDefaultImageTag(selectedProcessItem));
            tagText.setEnabled(true);
        }
    }

    private void addDockerOptionsListener() {
        ModifyListener optionListener = new ModifyListener() {

            @Override
            public void modifyText(ModifyEvent e) {
                if (remoteRadio.getSelection() && !isOptionValid(hostText, hostLabel.getText())) {
                    return;
                }
                if (!isOptionValid(imageText, imageLabel.getText())) {
                    return;
                }
                if (!isOptionValid(tagText, tagLabel.getText())) {
                    return;
                }
            }
        };

        hostText.addModifyListener(optionListener);
        imageText.addModifyListener(optionListener);
        tagText.addModifyListener(optionListener);

        remoteRadio.addSelectionListener(new SelectionAdapter() {

            @Override
            public void widgetSelected(SelectionEvent e) {
                hostText.setEnabled(remoteRadio.getSelection());
                if (remoteRadio.getSelection() && !isOptionValid(hostText, hostLabel.getText())) {
                    return;
                }
                if (!isOptionValid(imageText, imageLabel.getText())) {
                    return;
                }
                if (!isOptionValid(tagText, tagLabel.getText())) {
                    return;
                }
            }

        });
    }

    private boolean isOptionValid(Text text, String label) {
        boolean isValid = false;
        if (StringUtils.isBlank(text.getText())) {
            setErrorMessage(
                    org.talend.repository.i18n.Messages.getString("JavaJobScriptsExportWSWizardPage.DOCKER.errorMsg", label)); //$NON-NLS-1$
            setPageComplete(false);
            isValid = false;
        } else {
            setErrorMessage(null);
            setPageComplete(true);
            isValid = true;
        }
        return isValid;
    }

    private void restoreWidgetValuesForImage() {

        IDialogSettings settings = getDialogSettings();

        String remoteHost = settings.get(JavaJobScriptsExportWizardPage.STORE_DOCKER_REMOTE_HOST);
        if (StringUtils.isNotBlank(remoteHost)) {
            hostText.setText(remoteHost);
        }
        boolean isRemote = settings.getBoolean(JavaJobScriptsExportWizardPage.STORE_DOCKER_IS_REMOTE_HOST);
        localRadio.setSelection(!isRemote);
        remoteRadio.setSelection(isRemote);
        hostText.setEnabled(isRemote);
    }

    @Override
    public void createOptions(final Composite optionsGroup, Font font) {
        optionsGroupComposite = optionsGroup;
        optionsGroupFont = font;

        createOptionsForKar(optionsGroup, font);
        // createOptionForDockerImage(optionsGroup, font);

        if ("ROUTE_MICROSERVICE".equals(
                getProcessItem().getProperty().getAdditionalProperties().get(TalendProcessArgumentConstant.ARG_BUILD_TYPE))) {
            createDockerOptions(optionsGroup);
            restoreWidgetValuesForImage();
        }

        restoreWidgetValuesForKar();
    }

    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.ui.internal.wizards.datatransfer.WizardFileSystemResourceExportPage1#createDestinationGroup(org.
     * eclipse.swt.widgets.Composite)
     */
    @Override
    protected void createDestinationGroup(Composite parent) {
        Font font = parent.getFont();
        // destination specification group
        Composite destinationSelectionGroup = new Composite(parent, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.numColumns = 3;
        destinationSelectionGroup.setLayout(layout);
        destinationSelectionGroup.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL));
        destinationSelection