package com.bradmcevoy.http;

import com.bradmcevoy.http.AuthenticationService.AuthStatus;
import com.bradmcevoy.http.Request.Method;
import com.bradmcevoy.http.Response.Status;
import com.bradmcevoy.http.exceptions.BadRequestException;
import com.bradmcevoy.http.exceptions.ConflictException;
import com.bradmcevoy.http.exceptions.NotAuthorizedException;
import com.bradmcevoy.http.http11.Http11ResponseHandler;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author brad
 */
public class ResourceHandlerHelper {

    private final static Logger log = LoggerFactory.getLogger( ResourceHandlerHelper.class );
    /**
     * request attribute name for the parameters map
     */
    public static final String ATT_NAME_PARAMS = "_params";
    /**
     * request attribute name for the files map
     */
    public static final String ATT_NAME_FILES = "_files";
    private final HandlerHelper handlerHelper;
    private final Http11ResponseHandler responseHandler;
    private UrlAdapter urlAdapter = new UrlAdapterImpl();

    public ResourceHandlerHelper( HandlerHelper handlerHelper, Http11ResponseHandler responseHandler ) {
        if( responseHandler == null )
            throw new IllegalArgumentException( "responseHandler may not be null" );
        if( handlerHelper == null )
            throw new IllegalArgumentException( "handlerHelper may not be null" );
        this.handlerHelper = handlerHelper;
        this.responseHandler = responseHandler;
    }

    public void process( HttpManager manager, Request request, Response response, ResourceHandler handler ) throws NotAuthorizedException, ConflictException, BadRequestException {
        // need a linked hash map to preserve ordering of params
        Map<String, String> params = new LinkedHashMap<String, String>();

        Map<String, FileItem> files = new HashMap<String, FileItem>();

        try {
            request.parseRequestParameters( params, files );
        } catch( RequestParseException ex ) {
            log.warn( "exception parsing request. probably interrupted upload", ex );
            return;
        }
        request.getAttributes().put( ATT_NAME_PARAMS, params );
        request.getAttributes().put( ATT_NAME_FILES, files );

        if( !handlerHelper.checkExpects( responseHandler, request, response ) ) {
            return;
        }
        String host = request.getHostHeader();
        String url = urlAdapter.getUrl( request );
        //log.debug( "find resource: path: " + url + " host: " + host );
        Resource r = manager.getResourceFactory().getResource( host, url );
        if( r == null ) {
            responseHandler.respondNotFound( response, request );
            return;
        }
        handler.processResource( manager, request, response, r );
    }

    public void processResource( HttpManager manager, Request request, Response response, Resource resource, ExistingEntityHandler handler ) throws NotAuthorizedException, ConflictException, BadRequestException {
        processResource( manager, request, response, resource, handler, false, null, null );
    }

    public void processResource( HttpManager manager, Request request, Response response, Resource resource, ExistingEntityHandler handler, Map<String, String> params, Map<String, FileItem> files ) throws NotAuthorizedException, ConflictException, BadRequestException {
        processResource( manager, request, response, resource, handler, false, params, files );
    }

    public void processResource( HttpManager manager, Request request, Response response, Resource resource, ExistingEntityHandler handler, boolean allowRedirect, Map<String, String> params, Map<String, FileItem> files ) throws NotAuthorizedException, ConflictException, BadRequestException {
        log.trace( "processResource" );
        long t = System.currentTimeMillis();
        try {

            manager.onProcessResourceStart( request, response, resource );

            if( handlerHelper.isNotCompatible( resource, request.getMethod() ) || !handler.isCompatible( resource ) ) {
                if( log.isInfoEnabled() ) {
                    log.info( "resource not compatible. Resource class: " + resource.getClass() + " handler: " + handler.getClass() );
                }
                responseHandler.respondMethodNotImplemented( resource, response, request );
                return;
            }

            if( !handlerHelper.checkAuthorisation( manager, resource, request ) ) {
                if( log.isInfoEnabled() ) {
                    log.info( "authorisation failed. respond with: " + responseHandler.getClass().getCanonicalName() + " resource: " + resource.getClass().getCanonicalName() );
                }
                responseHandler.respondUnauthorised( resource, response, request );
                return;
            }

            // redirect check must be after authorisation, because the check redirect
            // logic might depend on logged in user
            if( allowRedirect ) {
                log.trace( "check redirect" );
                if( handlerHelper.doCheckRedirect( responseHandler, request, response, resource ) ) {
                    return;
                }
            }


            // Do not lock on POST requests. It is up to the application to decide whether or not
            // a POST requires a lock
            if( request.getMethod().isWrite && request.getMethod() != Method.POST ) {
                if( handlerHelper.isLockedOut( request, resource ) ) {
                    response.setStatus( Status.SC_LOCKED ); // replace with responsehandler method
                    return;
                }
            }

            handler.processExistingResource( manager, request, response, resource );
        } finally {
            t = System.currentTimeMillis() - t;
            manager.onProcessResourceFinish( request, response, resource, t );
        }
    }

    public boolean isNotCompatible( Resource r, Method m ) {
        return handlerHelper.isNotCompatible( r, m );
    }

    public boolean isLockedOut( Request inRequest, Resource inResource ) {
        return handlerHelper.isLockedOut( inRequest, inResource );
    }

    public AuthStatus checkAuthentication( HttpManager manager, Resource resource, Request request ) {
        return handlerHelper.checkAuthentication( manager, resource, request );
    }

    public UrlAdapter getUrlAdapter() {
        return urlAdapter;
    }

    public void setUrlAdapter( UrlAdapter urlAdapter ) {
        this.urlAdapter = urlAdapter;
    }
}

@@ -4480,37 +4480,53 @@
  %7D%0A%0A            
-if( !
+boolean authorised = 
 handlerHelper.ch
@@ -4571,20 +4571,18 @@
 equest )
- ) %7B
+;%0A
 %0A       
@@ -4590,286 +4590,213 @@
     
-    if( log.isInfoEnabled() ) %7B%0A                    log.info( %22authorisation failed. respond with: %22 + responseHandler.getClass().getCanonicalName() + %22 resource: %22 + resource.getClass().getCanonicalName() );%0A                %7D%0A                responseHandler.
+// redirect check must be after authorisation, because the check redirect%0A            // logic might depend on logged in user%0A            // but the actual redirection must be before we 
 respond
-U
+ u
 na
-u
 thorised
 ( re
@@ -4795,217 +4795,140 @@
 ised
-( resource, response, request );%0A                return;%0A            %7D%0A%0A            // redirect check must be after authorisation, because the check redirect%0A            // logic might depend on logged in user
+, because%0A            // in some cases we might want to pre-empt the unauthorised status and redirect%0A            // to a login page
 %0A   
@@ -5168,16 +5168,410 @@
      %7D%0A%0A
+            if( !authorised ) %7B%0A                if( log.isInfoEnabled() ) %7B%0A                    log.info( %22authorisation failed. respond with: %22 + responseHandler.getClass().getCanonicalName() + %22 resource: %22 + resource.getClass().getCanonicalName() );%0A                %7D%0A                responseHandler.respondUnauthorised( resource, response, request );%0A                return;%0A            %7D%0A%0A
 %0A       

put checkredirect after authorisation