/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Neofonie GmbH
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package de.neofonie.surlgen.processor.core;

import com.helger.jcodemodel.JBlock;
import com.helger.jcodemodel.JMethod;
import com.helger.jcodemodel.JVar;
import org.springframework.web.bind.annotation.MatrixVariable;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;

import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import java.util.List;
import java.util.logging.Logger;

enum TypeEnum {
    URL_RELEVANT,
    MODEL_ATTRIBUTE {
        @Override
        public void handleUriComponentsBuilderPostRequest(JMethod method, JVar uriComponentsBuilder, VariableElement variableElement) {

            TypeMirror typeMirror = variableElement.asType();
            if (typeMirror.getKind() == TypeKind.DECLARED) {
                DeclaredType declaredType = (DeclaredType) typeMirror;
                JVar param = method.param(ClassWriter.ref(declaredType.asElement().toString()), variableElement.getSimpleName().toString());
                JBlock block = method.body()._if(param.neNull())._then();
//                JBlock block = method.body();
                List<? extends Element> elements = declaredType.asElement().getEnclosedElements();
                for (Element element : elements) {
                    handleElement(block, uriComponentsBuilder, element, param);
                }
            }
        }

        private void handleElement(JBlock body, JVar uriComponentsBuilder, Element element, JVar param) {
            if (!(element instanceof ExecutableElement)
                    || !element.getSimpleName().toString().startsWith("get")) {
                return;
            }
            ExecutableElement executableElement = (ExecutableElement) element;
            if (!executableElement.getParameters().isEmpty()
                    || executableElement.getReturnType().getKind() == TypeKind.VOID
                    || !executableElement.getModifiers().contains(Modifier.PUBLIC)
                    || executableElement.getModifiers().contains(Modifier.STATIC)) {
                return;
            }

            String name = CamelCaseUtils.firstCharLowerCased(element.getSimpleName().toString().substring(3));

//            doWithModel.queryParam("fooo", "bar", "blub");

            JVar var = body.decl(ClassWriter.ref(Object.class), name).init(param.invoke(executableElement.getSimpleName().toString()));
            body._if(var.neNull())._then()
                    .invoke(uriComponentsBuilder, "queryParam").arg(name)
                    .arg(var);

        }
    },
    NOT_SUPPORTED,
    OTHER;

    private static final Logger log = Logger.getLogger(TypeEnum.class.getCanonicalName());

    static TypeEnum getType(VariableElement variableElement) {
        if (variableElement.getAnnotation(RequestParam.class) != null) {
            return URL_RELEVANT;
        }
        if (variableElement.getAnnotation(PathVariable.class) != null) {
            return URL_RELEVANT;
        }
        //ModelAttribute is currently not implemented in MvcUriComponentsBuilder - so we cant support this
        if (variableElement.getAnnotation(ModelAttribute.class) != null) {
            return MODEL_ATTRIBUTE;
        }
        //MatrixVariable is currently not implemented in MvcUriComponentsBuilder - so we cant support this
        if (variableElement.getAnnotation(MatrixVariable.class) != null) {
            log.info("MatrixVariable currently isnt supported in MvcUriComponentsBuilder");
            return NOT_SUPPORTED;
        }
        return OTHER;
    }

    public boolean isRelevantForUrl() {
        return this == URL_RELEVANT || this == MODEL_ATTRIBUTE;
    }

    public void handleUriComponentsBuilderPostRequest(JMethod method, JVar uriComponentsBuilder, VariableElement variableElement) {
    }
}

@@ -2531,56 +2531,8 @@
 ();%0A
-//                JBlock block = method.body();%0A
     
@@ -3684,17 +3684,16 @@
 blub%22);%0A
-%0A
         

add ModelAttribute