// Path: compiller/src/main/java/com/yheriatovych/reductor/processor/Env.java
// public class Env {
//     private final Types types;
//     private final Elements elements;
//     private final Messager messager;
//     private final Filer filer;
// 
//     public Env(Types types, Elements elements, Messager messager, Filer filer) {
//         this.types = types;
//         this.elements = elements;
//         this.messager = messager;
//         this.filer = filer;
//     }
// 
//     public void printError(Element element, String message, Object... args) {
//         printMessage(Diagnostic.Kind.ERROR, element, message, args);
//     }
// 
//     private void printMessage(Diagnostic.Kind level, Element element, String message, Object... args) {
//         messager.printMessage(level, String.format(message, args), element);
//     }
// 
//     public Types getTypes() {
//         return types;
//     }
// 
//     public Filer getFiler() {
//         return filer;
//     }
// 
//     public String getPackageName(Element element) {
//         return elements.getPackageOf(element).getQualifiedName().toString();
//     }
// 
//     public TypeMirror asType(Class<?> clazz) {
//         return elements.getTypeElement(clazz.getCanonicalName())
//                 .asType();
//     }
// 
//     public Elements getElements() {
//         return elements;
//     }
// }
// 
// Path: compiller/src/main/java/com/yheriatovych/reductor/processor/ValidationException.java
// public class ValidationException extends Exception {
//     private final Element element;
//     private final String message;
// 
//     public ValidationException(Element element, String message, Object... args) {
//         this.element = element;
//         this.message = String.format(message, args);
//     }
// 
//     public Element getElement() {
//         return element;
//     }
// 
//     @Override
//     public String getMessage() {
//         return message;
//     }
// 
// }
// 
// Path: compiller/src/main/java/com/yheriatovych/reductor/processor/ValidationUtils.java
// public class ValidationUtils {
//     public static void validateReturnsState(Env env, TypeMirror stateType, ExecutableElement element) throws ValidationException {
//         if (!env.getTypes().isAssignable(element.getReturnType(), stateType)) {
//             throw new ValidationException(element, "Method %s should return type assignable to state type %s", element, stateType);
//         }
//     }
// 
//     public static void validateIsNotPrivate(ExecutableElement element) throws ValidationException {
//         if (element.getModifiers().contains(Modifier.PRIVATE)) {
//             throw new ValidationException(element, "%s has 'private' modifier and is not accessible from child classes", element);
//         }
//     }
// }


import com.yheriatovych.reductor.annotations.AutoReducer;
import com.yheriatovych.reductor.processor.Env;
import com.yheriatovych.reductor.processor.ValidationException;
import com.yheriatovych.reductor.processor.ValidationUtils;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.type.TypeMirror;
package com.yheriatovych.reductor.processor.autoreducer;



public class AutoReducerInit {
    public final ExecutableElement executableElement;

    private AutoReducerInit(ExecutableElement executableElement) {
        this.executableElement = executableElement;
    }

    public String getName() {
        return executableElement.getSimpleName().toString();
    }

    public static AutoReducerInit parse(Env env, ExecutableElement executableElement, TypeMirror stateType) throws ValidationException {
        if (executableElement.getAnnotation(AutoReducer.Action.class) != null) {
            throw new ValidationException(executableElement, "Method %s should be may be annotated" +
                    " with either @AutoReducer.InitialState or @AutoReducer.Action but not both", executableElement);
        }

        ValidationUtils.validateReturnsState(env, stateType, executableElement);
        ValidationUtils.validateIsNotPrivate(executableElement);

// Path: compiller/src/main/java/com/yheriatovych/reductor/processor/Env.java
// public class Env {
//     private final Types types;
//     private final Elements elements;
//     private final Messager messager;
//     private final Filer filer;
// 
//     public Env(Types types, Elements elements, Messager messager, Filer filer) {
//         this.types = types;
//         this.elements = elements;
//         this.messager = messager;
//         this.filer = filer;
//     }
// 
//     public void printError(Element element, String message, Object... args) {
//         printMessage(Diagnostic.Kind.ERROR, element, message, args);
//     }
// 
//     private void printMessage(Diagnostic.Kind level, Element element, String message, Object... args) {
//         messager.printMessage(level, String.format(message, args), element);
//     }
// 
//     public Types getTypes() {
//         return types;
//     }
// 
//     public Filer getFiler() {
//         return filer;
//     }
// 
//     public String getPackageName(Element element) {
//         return elements.getPackageOf(element).getQualifiedName().toString();
//     }
// 
//     public TypeMirror asType(Class<?> clazz) {
//         return elements.getTypeElement(clazz.getCanonicalName())
//                 .asType();
//     }
// 
//     public Elements getElements() {
//         return elements;
//     }
// }
// 
// Path: compiller/src/main/java/com/yheriatovych/reductor/processor/ValidationException.java
// public class ValidationException extends Exception {
//     private final Element element;
//     private final String message;
// 
//     public ValidationException(Element element, String message, Object... args) {
//         this.element = element;
//         this.message = String.format(message, args);
//     }
// 
//     public Element getElement() {
//         return element;
//     }
// 
//     @Override
//     public String getMessage() {
//         return message;
//     }
// 
// }
// 
// Path: compiller/src/main/java/com/yheriatovych/reductor/processor/ValidationUtils.java
// public class ValidationUtils {
//     public static void validateReturnsState(Env env, TypeMirror stateType, ExecutableElement element) throws ValidationException {
//         if (!env.getTypes().isAssignable(element.getReturnType(), stateType)) {
//             throw new ValidationException(element, "Method %s should return type assignable to state type %s", element, stateType);
//         }
//     }
// 
//     public static void validateIsNotPrivate(ExecutableElement element) throws ValidationException {
//         if (element.getModifiers().contains(Modifier.PRIVATE)) {
//             throw new ValidationException(element, "%s has 'private' modifier and is not accessible from child classes", element);
//         }
//     }
// }


// Path: compiller/src/main/java/com/yheriatovych/reductor/processor/autoreducer/AutoReducerInit.java
import com.yheriatovych.reductor.annotations.AutoReducer;
import com.yheriatovych.reductor.processor.Env;
import com.yheriatovych.reductor.processor.ValidationException;
import com.yheriatovych.reductor.processor.ValidationUtils;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.type.TypeMirror;

package com.yheriatovych.reductor.processor.autoreducer;



public class AutoReducerInit {
    public final ExecutableElement executableElement;

    private AutoReducerInit(ExecutableElement executableElement) {
        this.executableElement = executableElement;
    }

    public String getName() {
        return executableElement.getSimpleName().toString();
    }

    public static AutoReducerInit parse(Env env, ExecutableElement executableElement, TypeMirror stateType) throws ValidationException {
        if (executableElement.getAnnotation(AutoReducer.Action.class) != null) {
            throw new ValidationException(executableElement, "Method %s should be may be annotated" +
                    " with either @AutoReducer.InitialState or @AutoReducer.Action but not both", executableElement);
        }

        ValidationUtils.validateReturnsState(env, stateType, executableElement);
        ValidationUtils.validateIsNotPrivate(executableElement);

        int paramsCount = executableElement.getParameters().size();