package io.subutai.core.hubmanager.impl.environment.state;


import java.security.PrivilegedAction;

import javax.security.auth.Subject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.apache.commons.lang3.StringUtils;

import io.subutai.core.hubmanager.api.exception.HubManagerException;
import io.subutai.core.hubmanager.api.RestResult;
import io.subutai.core.identity.api.IdentityManager;
import io.subutai.core.identity.api.model.Session;
import io.subutai.hub.share.dto.environment.EnvironmentPeerDto;
import io.subutai.hub.share.dto.environment.EnvironmentPeerDto.PeerState;

import static io.subutai.hub.share.dto.environment.EnvironmentPeerDto.PeerState.READY;
import static io.subutai.hub.share.dto.environment.EnvironmentPeerDto.PeerState.WAIT;


public abstract class StateHandler
{
    private static final String PATH = "/rest/v1/environments/%s/peers/%s";

    protected final Logger log = LoggerFactory.getLogger( getClass() );

    protected final Context ctx;

    private String description;


    protected StateHandler( Context ctx, String description )
    {
        this.ctx = ctx;
        this.description = description;
    }


    protected abstract Object doHandle( EnvironmentPeerDto peerDto ) throws HubManagerException;


    public void handle( final EnvironmentPeerDto peerDto )
    {
        String token = getToken( peerDto );

        Session session = ctx.identityManager.login( IdentityManager.TOKEN_ID, token );

        Subject.doAs( session.getSubject(), new PrivilegedAction<Void>()
        {
            @Override
            public Void run()
            {
                runAs( peerDto );

                return null;
            }
        } );
    }


    /**
     * Most of operations are performed with a Hub user account, i.e. using its token. But for some operations a peer
     * token may be required. For example, removing a user account after an environment destroy.
     */
    protected String getToken( EnvironmentPeerDto peerDto )
    {
        return peerDto.getUserToken().getToken();
    }


    private void runAs( EnvironmentPeerDto peerDto )
    {
        if ( canIgnoreState( peerDto ) )
        {
            log.info( "Ignoring state: {}", peerDto.getState() );

            return;
        }

        try
        {
            Object result = doHandle( peerDto );

            post( peerDto, result );
        }
        catch ( Exception e )
        {
            log.error( "Failed to process environment state: ", e );

            handleError( peerDto, e );
        }
    }


    protected boolean canIgnoreState( EnvironmentPeerDto peerDto )
    {
        PeerState state = peerDto.getState();

        return state == WAIT || state == READY;
    }


    protected RestResult<Object> post( EnvironmentPeerDto peerDto, Object body )
    {
        return ctx.restClient.post( path( PATH, peerDto ), body );
    }


    protected void handleError( EnvironmentPeerDto peerDto, Exception e )
    {
        peerDto.setError( description + ". " + e.getMessage() );

        ctx.restClient.post( path( PATH, peerDto ), peerDto );
    }


    protected String path( String format, EnvironmentPeerDto peerDto )
    {
        return StringUtils.countMatches( format, "%s" ) == 1 ?
               String.format( format, peerDto.getEnvironmentInfo().getId() ) :
               String.format( format, peerDto.getEnvironmentInfo().getId(), peerDto.getPeerId() );
    }


    protected void logStart()
    {
        log.info( "{} - START", description );
    }


    protected void logEnd()
    {
        log.info( "{} - END", description );
    }
}

@@ -54,16 +54,44 @@
 tate;%0A%0A%0A
+import java.io.IOException;%0A
 import j
@@ -159,16 +159,62 @@
 bject;%0A%0A
+import org.bouncycastle.openpgp.PGPException;%0A
 import o
@@ -528,24 +528,77 @@
 el.Session;%0A
+import io.subutai.core.identity.api.model.UserToken;%0A
 import io.su
@@ -1495,32 +1495,33 @@
 en( peerDto );%0A%0A
+%0A
         Session 
@@ -2150,35 +2150,147 @@
     
-return peerDto.getU
+try%0A        %7B%0A            UserToken userToken = ctx.envUserHelper.getUserTokenFromHub( peerDto.getOwnerId() );%0A            return u
 serToken
 ().g
@@ -2285,22 +2285,24 @@
 serToken
-()
 .get
+Full
 Token();
@@ -2302,16 +2302,177 @@
 oken();%0A
+        %7D%0A        catch ( HubManagerException %7C PGPException %7C IOException e )%0A        %7B%0A            log.error( e.getMessage() );%0A        %7D%0A        return null;%0A
     %7D%0A%0A%0A

use get token from Hub, helper method