/*
 * RHQ Management Platform
 * Copyright (C) 2005-2010 Red Hat, Inc.
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
package org.rhq.enterprise.gui.coregui.client.bundle.create;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.VerticalAlignment;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.Label;
import com.smartgwt.client.widgets.form.events.FormSubmitFailedEvent;
import com.smartgwt.client.widgets.form.events.FormSubmitFailedHandler;
import com.smartgwt.client.widgets.layout.HLayout;
import com.smartgwt.client.widgets.layout.VLayout;

import org.rhq.enterprise.gui.coregui.client.CoreGUI;
import org.rhq.enterprise.gui.coregui.client.components.HeaderLabel;
import org.rhq.enterprise.gui.coregui.client.components.upload.BundleFileUploadForm;
import org.rhq.enterprise.gui.coregui.client.components.upload.DynamicFormHandler;
import org.rhq.enterprise.gui.coregui.client.components.upload.DynamicFormSubmitCompleteEvent;
import org.rhq.enterprise.gui.coregui.client.components.wizard.AbstractWizardStep;
import org.rhq.enterprise.gui.coregui.client.gwt.BundleGWTServiceAsync;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
import org.rhq.enterprise.gui.coregui.client.util.message.Message;
import org.rhq.enterprise.gui.coregui.client.util.message.Message.Severity;

public class BundleUploadDataStep extends AbstractWizardStep {

    private final AbstractBundleCreateWizard wizard;
    private final BundleGWTServiceAsync bundleServer = GWTServiceLookup.getBundleService();
    private ArrayList<BundleFileUploadForm> uploadForms;
    private Boolean noFilesNeedToBeUploaded = null; // will be non-null when we know the answer

    public BundleUploadDataStep(AbstractBundleCreateWizard bundleCreationWizard) {
        this.wizard = bundleCreationWizard;
    }

    public Canvas getCanvas() {
        final VLayout mainLayout = new VLayout();
        mainLayout.setMargin(Integer.valueOf(20));
        mainLayout.setWidth100();
        mainLayout.setHeight(10);

        bundleServer.getAllBundleVersionFilenames(this.wizard.getBundleVersion().getId(),
            new AsyncCallback<HashMap<String, Boolean>>() {

                public void onSuccess(HashMap<String, Boolean> result) {
                    wizard.setAllBundleFilesStatus(result);
                    prepareForm(mainLayout);
                    // If no files need to be uploaded, we could skip immediately to the next step.
                    // I commented this out because if we do this, it prohibits someone
                    // going from the summary step back (via previous button) to here
                    // without it immediately going forward again to summary. I think its
                    // OK for the user to see a page that says, "no more files need to be uploaded"
                    // and have to hit the Next button to see the summary.
                    /*
                    if (noFilesNeedToBeUploaded) {
                        wizard.getView().incrementStep();
                    }
                    */
                }

                public void onFailure(Throwable caught) {
                    wizard.setAllBundleFilesStatus(null);
                    CoreGUI.getErrorHandler().handleError("Cannot obtain bundle file information from server", caught);
                }
            });

        return mainLayout;
    }

    public boolean nextPage() {
        wizard.getView().hideMessage();

        return isFinished();
    }

    public boolean previousPage() {
        wizard.getView().hideMessage();

        for (BundleFileUploadForm uploadForm : this.uploadForms) {
            if (uploadForm.isUploadInProgress()) {
                handleUploadError("[" + uploadForm.getName()
                    + "] Upload is in progress... This can take several minutes for large files.", false);
                return false;
            }
        }

        return true;
    }

    public String getName() {
        return "Upload Bundle Files";
    }

    private boolean isFinished() {
        if (noFilesNeedToBeUploaded != null && noFilesNeedToBeUploaded.booleanValue()) {
            return true;
        }

        if (wizard.getAllBundleFilesStatus() == null) {
            return false;
        }

        boolean needToUpload = false;
        for (BundleFileUploadForm uploadForm : this.uploadForms) {
            if (uploadForm.isUploadInProgress()) {
                handleUploadError("[" + uploadForm.getName()
                    + "] Upload is in progress... This can take several minutes for large files.", false);
                needToUpload = true;
            } else if (uploadForm.getUploadResult() == null) {
                needToUpload = true;
                uploadForm.submitForm();
                // on certain errors the form may never be submitted, report these errors outside submit handlers
                handleUploadError(uploadForm.getUploadError(), false);
            }
        }
        if (needToUpload) {
            return false;
        }

        if (wizard.getAllBundleFilesStatus().containsValue(Boolean.FALSE)) {
            return false;
        }
        return true;
    }

    private void prepareForm(VLayout mainLayout) {

        final HashMap<String, Boolean> allFilesStatus = wizard.getAllBundleFilesStatus();
        noFilesNeedToBeUploaded = Boolean.TRUE;

        if (null != allFilesStatus && !allFilesStatus.isEmpty()) {
            for (Map.Entry<String, Boolean> entry : allFilesStatus.entrySet()) {
                if (!entry.getValue()) {
                    noFilesNeedToBeUploaded = Boolean.FALSE;
                    break;
                }
            }
        }

        if (noFilesNeedToBeUploaded) {
            HeaderLabel label = new HeaderLabel("No additional files need to be uploaded for this bundle");
            label.setWidth100();
            mainLayout.addMember(label);
            uploadForms = null;
            return;
        }

        noFilesNeedToBeUploaded = Boolean.FALSE;
        uploadForms = new ArrayList<BundleFileUploadForm>();

        for (Map.Entry<String, Boolean> entry : allFilesStatus.entrySet()) {
            String fileToBeUploaded = entry.getKey();
            Boolean isAlreadyUploaded = entry.getValue();

            HLayout indivLayout = new HLayout();
            indivLayout.setWidth100();
            indivLayout.setAutoHeight();

            Label nameLabel = new Label(fileToBeUploaded + ": ");
            nameLabel.setWidth("*");
            nameLabel.setAlign(Alignment.RIGHT);
            nameLabel.setLayoutAlign(VerticalAlignment.CENTER);
            indivLayout.addMember(nameLabel);

            final BundleFileUploadForm uploadForm = new BundleFileUploadForm(this.wizard.getBundleVersion(),
                fileToBeUploaded, false, (isAlreadyUploaded) ? Boolean.TRUE : null);
            uploadForm.setWidth("75%");
            indivLayout.addMember(uploadForm);

            uploadForm.addFormHandler(new DynamicFormHandler() {
                public void onSubmitComplete(DynamicFormSubmitCompleteEvent event) {
                    String results = event.getResults();
                    if (!results.contains("Failed to upload bundle file")) {
                        allFilesStatus.put(uploadForm.getName(), Boolean.TRUE);
                    } else {
                        allFilesStatus.put(uploadForm.getName(), Boolean.FALSE);
                        String errorMessage = uploadForm.getUploadError();
                        handleUploadError(errorMessage, true);
                    }
                }
            });
            uploadForm.addFormSubmitFailedHandler(new FormSubmitFailedHandler() {
                public void onFormSubmitFailed(FormSubmitFailedEvent event) {
                    allFilesStatus.put(uploadForm.getName(), Boolean.FALSE);
                    CoreGUI.getMessageCenter().notify(
                        new Message("Failed to upload file", null, Message.Severity.Error));
                }
            });

            uploadForms.add(uploadForm);

            mainLayout.addMember(indivLayout);
        }

        return;
    }

    private void handleUploadError(String errorMessage, boolean sendToMessageCenter) {
        if (null != errorMessage) {
            wizard.getView().showMessage(errorMessage);
        } else {
            errorMessage = "";
        }

        if (sendToMessageCenter) {
            CoreGUI.getMessageCenter().notify(
                new Message("Failed to upload bundle distribution file. " + errorMessage, Severity.Error));
        }
    }

}
