package org.zstack.console;

import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.zstack.core.config.GlobalConfigFacade;
import org.zstack.core.errorcode.ErrorFacade;
import org.zstack.header.console.*;
import org.zstack.header.core.ReturnValueCompletion;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.host.HypervisorType;
import org.zstack.header.identity.SessionInventory;
import org.zstack.header.rest.JsonAsyncRESTCallback;
import org.zstack.header.rest.RESTFacade;
import org.zstack.header.vm.VmInstanceInventory;
import org.zstack.utils.URLBuilder;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;

import java.net.URI;
import java.util.concurrent.TimeUnit;

/**
 * Created with IntelliJ IDEA.
 * User: frank
 * Time: 9:07 PM
 * To change this template use File | Settings | File Templates.
 */
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
public class ConsoleProxyBase implements ConsoleProxy {
    private static final CLogger logger = Utils.getLogger(ConsoleProxyBase.class);
    private ConsoleProxyInventory self;

    @Autowired
    private RESTFacade restf;
    @Autowired
    private ConsoleManager consoleMgr;
    @Autowired
    private ErrorFacade errf;

    private final int agentPort;

    public ConsoleProxyBase(ConsoleProxyVO vo, int agentPort) {
        self = ConsoleProxyInventory.valueOf(vo);
        this.agentPort = agentPort;
    }

    public ConsoleProxyBase(ConsoleProxyInventory inv, int agentPort) {
        self = inv;
        this.agentPort = agentPort;
    }

    private void doEstablish(URI uri, final ReturnValueCompletion<ConsoleProxyInventory> completion) {
        final String targetHostname = uri.getHost();
        final int targetPort = uri.getPort();

        int timeout = ConsoleGlobalConfig.PROXY_IDLE_TIMEOUT.value(Integer.class);

        ConsoleProxyCommands.EstablishProxyCmd cmd = new ConsoleProxyCommands.EstablishProxyCmd();
        cmd.setVmUuid(self.getVmInstanceUuid());
        cmd.setTargetHostname(targetHostname);
        cmd.setTargetPort(targetPort);
        cmd.setProxyHostname(self.getProxyHostname());
        cmd.setScheme(self.getScheme());
        cmd.setToken(self.getToken());
        cmd.setIdleTimeout(timeout);

        String agentUrl = URLBuilder.buildHttpUrl(self.getAgentIp(), agentPort, ConsoleConstants.CONSOLE_PROXY_ESTABLISH_PROXY_PATH);
        restf.asyncJsonPost(agentUrl, cmd, new JsonAsyncRESTCallback<ConsoleProxyCommands.EstablishProxyRsp>(completion) {
            @Override
            public void fail(ErrorCode err) {
                completion.fail(err);
            }

            @Override
            public void success(ConsoleProxyCommands.EstablishProxyRsp ret) {
                if (ret.isSuccess()) {
                    self.setTargetHostname(targetHostname);
                    self.setTargetPort(targetPort);
                    self.setProxyPort(ret.getProxyPort());
                    completion.success(self);
                } else {
                    completion.fail(errf.stringToOperationError(ret.getError()));
                }
            }

            @Override
            public Class<ConsoleProxyCommands.EstablishProxyRsp> getReturnClass() {
                return ConsoleProxyCommands.EstablishProxyRsp.class;
            }
        }, TimeUnit.SECONDS, 300);
    }

    @Override
    public void establishProxy(final SessionInventory session, final VmInstanceInventory vm, final ReturnValueCompletion<ConsoleProxyInventory> completion) {
        ConsoleHypervisorBackend bkd = consoleMgr.getHypervisorConsoleBackend(HypervisorType.valueOf(vm.getHypervisorType()));
        bkd.generateConsoleUrl(vm, new ReturnValueCompletion<URI>(completion) {

            @Override
            public void success(URI uri) {
                doEstablish(uri, completion);
            }

            @Override
            public void fail(ErrorCode errorCode) {
                completion.fail(errorCode);
            }
        });

    }

    @Override
    public void checkAvailability(final ReturnValueCompletion<Boolean> completion) {
        ConsoleProxyCommands.CheckAvailabilityCmd cmd = new ConsoleProxyCommands.CheckAvailabilityCmd();
        cmd.setProxyHostname(self.getProxyHostname());
        cmd.setProxyPort(self.getProxyPort());
        cmd.setTargetHostname(self.getTargetHostname());
        cmd.setTargetPort(self.getTargetPort());
        cmd.setProxyIdentity(self.getProxyIdentity());
        cmd.setToken(self.getToken());
        cmd.setScheme(self.getScheme());
        restf.asyncJsonPost(URLBuilder.buildHttpUrl(self.getAgentIp(), agentPort, ConsoleConstants.CONSOLE_PROXY_CHECK_PROXY_PATH),
                cmd, new JsonAsyncRESTCallback<ConsoleProxyCommands.CheckAvailabilityRsp>(completion) {
            @Override
            public void fail(ErrorCode err) {
                completion.fail(err);
            }

            @Override
            public void success(ConsoleProxyCommands.CheckAvailabilityRsp ret) {
                if (ret.isSuccess()) {
                    completion.success(ret.getAvailable());
                } else {
                    String err = String.format("unable to check console proxy availability, because %s", ret.getError());
                    logger.warn(err);
                    completion.fail(errf.stringToOperationError(err));
                }
            }

            @Override
            public Class<ConsoleProxyCommands.CheckAvailabilityRsp> getReturnClass() {
                return ConsoleProxyCommands.CheckAvailabilityRsp.class;
            }

        }, TimeUnit.SECONDS, 300);
    }
}

@@ -214,24 +214,68 @@
 figurable;%0D%0A
+import org.zstack.core.CoreGlobalProperty;%0D%0A
 import org.z
@@ -2328,32 +2328,219 @@
 t(targetPort);%0D%0A
+        if (!%220.0.0.0%22.equals(CoreGlobalProperty.CONSOLE_PROXY_OVERRIDDEN_IP)) %7B%0D%0A            cmd.setProxyHostname(CoreGlobalProperty.CONSOLE_PROXY_OVERRIDDEN_IP);%0D%0A        %7D else %7B%0D%0A    
         cmd.setP
@@ -2571,32 +2571,43 @@
 xyHostname());%0D%0A
+        %7D%0D%0A
         cmd.setS

fix consoleproxy IP binding issue