/*
 * Copyright 2017 Lime - HighTech Solutions s.r.o.
 *
 * Licensed 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
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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 io.getlime.security.powerauth.lib.credentials.exception;

import io.getlime.security.powerauth.lib.credentials.model.entity.ErrorModel;
import io.getlime.security.powerauth.lib.nextstep.model.base.Response;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

/**
 * Controller advice responsible for default exception resolving.
 *
 * @author Roman Strobl
 */
@ControllerAdvice
public class DefaultExceptionResolver {

    /**
     * Handling of unexpected errors.
     * @return Response with ErrorModel.
     */
    @ExceptionHandler(Throwable.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public @ResponseBody Response<ErrorModel> handleDefaultException(Throwable t) {
        ErrorModel error = new ErrorModel(ErrorModel.Code.ERROR_GENERIC, "Unknown Error");
        return new Response<>(Response.Status.ERROR, error);
    }

    @ExceptionHandler(AuthenticationFailedException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public @ResponseBody Response<ErrorModel> handleAuthenticationError(AuthenticationFailedException ex) {
        // regular authentication failed error
        ErrorModel error = new ErrorModel(ErrorModel.Code.AUTHENTICATION_FAILED, ex.getMessage());
        return new Response<>(Response.Status.ERROR, error);
    }

    /**
     * Handling of validation errors.
     * @return Response with ErrorModel.
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public @ResponseBody Response<ErrorModel> handleDefaultException(MethodArgumentNotValidException ex) {
        ErrorModel error = new ErrorModel();
        error.setCode(ErrorModel.Code.INPUT_INVALID);
        StringBuilder errorBuilder = new StringBuilder();
        for (ObjectError objError: ex.getBindingResult().getAllErrors()) {
            for (String code: objError.getCodes()) {
                int lastErrorBuilderLength = errorBuilder.length();
                switch (code) {
                    case "username.empty":
                        errorBuilder.append("username is empty");
                        break;
                    case "password.empty":
                        errorBuilder.append("password is empty");
                        break;
                    case "username.long":
                        errorBuilder.append("username length exceeded maximum number of characters");
                        break;
                    case "password.long":
                        errorBuilder.append("password length exceeded maximum number of characters");
                        break;
                    case "type.unsupported":
                        errorBuilder.append("authentication type is not supported");
                        break;
                    default:
                        continue;
                }
                // add comma but only if some error message was added
                if (lastErrorBuilderLength != errorBuilder.length()) {
                    errorBuilder.append(", ");
                }
            }
        }
        String errors;
        if (errorBuilder.length() >= 2) {
            // strip trailing comma
            errors = errorBuilder.substring(0, errorBuilder.length() - 2);
        } else {
            errors = errorBuilder.toString();
        }
        error.setMessage("Input validation failed: " + errors);
        return new Response<>(Response.Status.ERROR, error);
    }

}

@@ -869,56 +869,8 @@
 us;%0A
-import org.springframework.http.ResponseEntity;%0A
 impo
@@ -1240,16 +1240,68 @@
 tatus;%0A%0A
+import java.util.ArrayList;%0Aimport java.util.List;%0A%0A
 /**%0A * C
@@ -1713,19 +1713,8 @@
 ion(
-Throwable t
 ) %7B%0A
@@ -2716,54 +2716,52 @@
     
+List%3C
 String
-Builder errorBuilder = new StringBuilder
+%3E errorMessages = new ArrayList%3C%3E
 ();%0A
@@ -2892,76 +2892,8 @@
 ) %7B%0A
-                int lastErrorBuilderLength = errorBuilder.length();%0A
     
@@ -2992,33 +2992,31 @@
    error
-Builder.append(%22u
+Messages.add(%22U
 sername 
@@ -3015,32 +3015,33 @@
 sername is empty
+.
 %22);%0A            
@@ -3131,33 +3131,31 @@
    error
-Builder.append(%22p
+Messages.add(%22P
 assword 
@@ -3162,16 +3162,17 @@
 is empty
+.
 %22);%0A    
@@ -3273,33 +3273,31 @@
 rror
-Builder.append(%22u
+Messages.add(%22U
 sername 
 leng
@@ -3296,52 +3296,17 @@
 ame 
-length exceeded maximum number of characters
+too long.
 %22);%0A
@@ -3411,33 +3411,31 @@
 rror
-Builder.append(%22p
+Messages.add(%22P
 assword 
 leng
@@ -3434,52 +3434,17 @@
 ord 
-length exceeded maximum number of characters
+too long.
 %22);%0A
@@ -3548,32 +3548,42 @@
    error
-Builder.append(%22
+Messages.add(%22Unsupported 
 authenti
@@ -3597,25 +3597,9 @@
 type
- is not supported
+.
 %22);%0A
@@ -3686,576 +3686,113 @@
     
-continue;%0A                %7D%0A                // add comma but only if some error message was added%0A                if (lastErrorBuilderLength != errorBuilder.length()) %7B%0A                    errorBuilder.append(%22, %22);%0A                %7D%0A            %7D%0A        %7D%0A        String errors;%0A        if (errorBuilder.length() %3E= 2) %7B%0A            // strip trailing comma%0A            errors = errorBuilder.substring(0, errorBuilder.length() - 2);%0A        %7D else %7B%0A            errors = errorBuilder.toString();%0A        %7D%0A       
+break;%0A                %7D%0A            %7D%0A        %7D%0A        error.setMessage(String.join(%22,%22,
  error
-.set
 Message
-(%22Input validation failed: %22 + error
 s
+)
 );%0A 

Implement more readable logic in validator