package dev.openshift.tapestry.angular.ws.service;
 
import dev.openshift.tapestry.angular.data.user.Token;
import dev.openshift.tapestry.angular.services.UserDAO;
import dev.openshift.tapestry.angular.entity.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.jboss.resteasy.util.Base64;
import org.slf4j.Logger;
import org.tynamo.security.services.SecurityService;

import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.util.*;


@Path("/app/user")
public class UserService
{
    private static final String AUTHORIZATION_PROPERTY = "Authorization";
    private static final String AUTHENTICATION_SCHEME = "Basic";

    @Inject
    private UserDAO userDatabase;

    @Inject
    private SecurityService securityService;

    @Inject
    private Logger LOG;


    @GET
    @Path("/users/{login}")
    @PermitAll
    public Response getUserByLogin(@PathParam("login") String login, @Context Request req)
    {
        Response.ResponseBuilder rb = Response.ok(userDatabase.getUserByLogin(login));
        return rb.build();
    }
     


    @PUT
    @Path("/users/{login}")
    @RolesAllowed("ADMIN")
    public Response updateUserById(@PathParam("login") String login)
    {
        //Update the User resource
        User user=userDatabase.getUserByLogin(login);
        return Response.status(200).build();
    }

    @GET
    @Path("/validate")
    @PermitAll
    public Response validate( @Context Request req)
    {
        Subject subject;
        try {
            subject = securityService.getSubject();
            if (subject.isAuthenticated()) {
                return Response.ok().build();
            }
        }
        catch (Exception e) {
            LOG.debug("User failed to log.");
        }
        return Response.status(Response.Status.BAD_REQUEST).entity("not Authenticated").build();
    }

    @POST
    @Path("/authentication")
    @Consumes("application/x-www-form-urlencoded")
    @PermitAll
    public Response postLogin(@FormParam("j_username") String username,@FormParam("j_password") String password) {
        Response.ResponseBuilder rb;

        Subject subject;
        try {
            subject = securityService.getSubject();
            if (!subject.isAuthenticated()) {
                UsernamePasswordToken token = new UsernamePasswordToken(username, password);
                subject.login(token);
                token.clear();
                String userPassword= username + ":" + password;
                String basicAuth = new String(Base64.encodeBytes(userPassword.getBytes()));
                Token cltToken = new Token();
                cltToken.setAccess_token("Basic "+basicAuth);
                cltToken.setExpires_in(1799);
                cltToken.setToken_type("bearer");
                cltToken.setScope("read write");
                rb = Response.ok(cltToken);
                //rb = Response.ok();
                return rb.build();

            } else {
                LOG.debug("User [" + subject.getPrincipal() + "] already authenticated.");
                if(subject.getPrincipal().toString().equals(username))
                {
                    rb = Response.ok();
                    return rb.build();
                }
            }
        } catch (Exception e) {
            LOG.debug("User failed to log.");
        }

        return Response.status(Response.Status.BAD_REQUEST).entity("invalid login or password").build();

    }




    @GET
    @Path("/account")
    @PermitAll
    public Response account( @Context Request req, @Context HttpHeaders headers)
    {
        String auth = headers.getHeaderString(AUTHORIZATION_PROPERTY);
        //Get encoded username and password
        final String encodedUserPassword = auth.replaceFirst(AUTHENTICATION_SCHEME + " ", "");

        //Decode username and password
        String usernameAndPassword;
        try {
            usernameAndPassword = new String(Base64.decode(encodedUserPassword));
        } catch (IOException e) {
            return Response.status(Response.Status.BAD_REQUEST).entity("invalid token").build();
        }

        //Split username and password tokens
        final StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, ":");
        final String username = tokenizer.nextToken();
        final String password = tokenizer.nextToken();

        Subject subject;
        try {

            subject = securityService.getSubject();
            if (!subject.isAuthenticated()) {
                return Response.status(Response.Status.BAD_REQUEST).entity("not authenticated").build();
            }
            String userNameFromSubject = subject.getPrincipal().toString();
            if(!userNameFromSubject.equals(username)){
                return Response.status(Response.Status.BAD_REQUEST).entity("invalid user or password").build();
            }

            User user = new User();
            user.setLogin(subject.getPrincipal().toString());
            List<String> roles =  new ArrayList<String>() ;
            roles.add("*");
            user.setRoles(roles);
            Response.ResponseBuilder rb = Response.ok(user);
            return rb.build();
        } catch (Exception e) {
            LOG.debug("User  failed to log.");
            return Response.status(Response.Status.BAD_REQUEST).entity("invalid user or password").build();

        }

    }

    @GET
    @Path("/logout")
    @PermitAll
    public Response logout( @Context Request req)
    {
        securityService.getSubject().logout();
        Response.ResponseBuilder rb = Response.ok();
        return rb.build();
    }
}
@@ -45,17 +45,136 @@
 rvice;%0D%0A
- 
+%0D%0Aimport dev.openshift.tapestry.angular.data.user.RoleConsts;%0D%0Aimport dev.openshift.tapestry.angular.data.user.RoleEnum;
 %0D%0Aimport
@@ -1648,15 +1648,29 @@
 wed(
-%22ADMIN%22
+RoleConsts.ADMIN_ROLE
 )%0D%0A 
@@ -3446,47 +3446,8 @@
 );%0D%0A
-                //rb = Response.ok();%0D%0A
     
@@ -5534,41 +5534,27 @@
 gin(
-subject.getPrincipal().toString()
+userNameFromSubject
 );%0D%0A
@@ -5630,23 +5630,206 @@
     
-roles.add(%22*%22);
+for (RoleEnum r: RoleEnum.values())%0D%0A            %7B%0D%0A                if(subject.hasRole(r.getRole()))%0D%0A                %7B%0D%0A                    roles.add(r.getRole());%0D%0A                %7D%0D%0A            %7D
 %0D%0A  

update UserService