/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jboss.installer.postinstall.task;

import com.google.auto.service.AutoService;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.PathAddress;
import org.jboss.dmr.ModelNode;
import org.jboss.installer.core.InstallationData;
import org.jboss.installer.postinstall.CliPostInstallTask;
import org.jboss.installer.postinstall.PostInstallTask;
import org.jboss.installer.postinstall.TaskPrinter;
import org.jboss.installer.postinstall.server.DomainServer;
import org.jboss.installer.postinstall.server.StandaloneServer;

import java.util.Locale;

import static org.jboss.as.controller.operations.common.Util.createEmptyOperation;
import static org.jboss.installer.core.LoggerUtils.taskLog;

@AutoService(PostInstallTask.class)
public class JsfDefaultLibraryTask implements CliPostInstallTask {
    @Override
    public boolean applyToStandalone(InstallationData data, StandaloneServer server, TaskPrinter printer) {
        final JsfLibraryTask.Config config = data.getConfig(JsfLibraryTask.Config.class);
        if (config.isMakeDefault()) {
            printer.print("tasks.jsf.started", server.currentConfiguration());
            final ModelNode setDefaultJsf = createDefaultJsfOp(config);
            try {
                server.execute(setDefaultJsf, "Set JSF default module");
            } catch (OperationFailedException e) {
                taskLog.error("CLI operation failed", e);
                printer.print("tasks.jsf.failed");
                printer.print(e);
                return false;
            }
            printer.print("tasks.jsf.finished");
        } else {
            printer.print("tasks.jsf.started", server.currentConfiguration());
            if (server.currentConfiguration().equals("standalone.xml")) {
                // unset the default jsf slot if it was set by JSF feature pack
                final ModelNode setDefaultJsf = removeDefaultJsfOp();
                try {
                    server.execute(setDefaultJsf, "Unset JSF default module");
                } catch (OperationFailedException e) {
                    taskLog.error("CLI operation failed", e);
                    printer.print("tasks.jsf.failed");
                    printer.print(e);
                    return false;
                }
            }

        }
        return true;
    }

    @Override
    public boolean applyToDomain(InstallationData data, DomainServer server, TaskPrinter printer) {
        final JsfLibraryTask.Config config = data.getConfig(JsfLibraryTask.Config.class);
        // only run on host.xml - the changes are applied to domain.xml
        if (server.currentConfiguration().equals("host.xml") && config.isMakeDefault()) {
            printer.print("tasks.jsf.started", server.currentConfiguration());
            final ModelNode setDefaultJsf = createDefaultJsfOp(config);
            try {
                server.executeOnProfiles(setDefaultJsf, "Set JSF default module");
            } catch (OperationFailedException e) {
                taskLog.error("CLI operation failed", e);
                printer.print("tasks.jsf.failed");
                printer.print(e);
                return false;
            }
            printer.print("tasks.jsf.finished");
        }
        return true;
    }

    private ModelNode createDefaultJsfOp(JsfLibraryTask.Config config) {
        final JsfLibraryTask.Config.JsfProject jsfProject = config.getJsfProject();
        final String jsfVersion = config.getJsfVersion()==null?"unknown":config.getJsfVersion();
        final ModelNode setDefaultJsf = createEmptyOperation("write-attribute",
                PathAddress.pathAddress("subsystem", "jsf"));
        setDefaultJsf.get("name").set("default-jsf-impl-slot");
        final String jsfSlotName;
        if (config.getJsfProject() == JsfLibraryTask.Config.JsfProject.MyFaces) {
            jsfSlotName = jsfProject.name().toLowerCase(Locale.ROOT);
        } else {
            jsfSlotName = jsfProject.name().toLowerCase(Locale.ROOT) + "-" + jsfVersion;
        }
        setDefaultJsf.get("value").set(jsfSlotName);
        return setDefaultJsf;
    }

    private ModelNode removeDefaultJsfOp() {
        final ModelNode removeDefaultJsf = createEmptyOperation("undefine-attribute",
                PathAddress.pathAddress("subsystem", "jsf"));
        removeDefaultJsf.get("name").set("default-jsf-impl-slot");
        return removeDefaultJsf;
    }

    @Override
    public String getName() {
        return "jsf_config.default_version.task.name";
    }

    @Override
    public String getSerializationName() {
        return "set-default-jsf-module";
    }
}
