// 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;
//     }
// 
// }


import com.google.auto.common.MoreElements;
import com.squareup.javapoet.TypeName;
import com.yheriatovych.reductor.annotations.ActionCreator;
import com.yheriatovych.reductor.processor.Env;
import com.yheriatovych.reductor.processor.ValidationException;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
package com.yheriatovych.reductor.processor.actioncreator;



public class ActionCreatorElement {
    public final List<ActionCreatorAction> actions;
    private final TypeElement typeElement;
    private Map<String, ActionCreatorAction> actionMap;

    private ActionCreatorElement(List<ActionCreatorAction> actions, TypeElement typeElement) {
        this.actions = actions;
        this.typeElement = typeElement;
        actionMap = new HashMap<>();
        for (ActionCreatorAction action : actions) {
            actionMap.put(action.actionType, action);
        }
    }

    public boolean hasAction(String actionType, List<? extends VariableElement> reducerArgs) {
        ActionCreatorAction actionCreator = actionMap.get(actionType);
        if (actionCreator == null || reducerArgs.size() != actionCreator.arguments.size()) return false;
        List<? extends VariableElement> arguments = actionCreator.arguments;
        for (int i = 0; i < arguments.size(); i++) {
            //we are doing black magic with checking if TypeName are equals
            //instead of checking if two TypeMirrors are equals because TypeMirrors can be different for the same type
            //happens when code is processed with several number of processing steps
            TypeName creatorArgType = actionCreator.argumentTypes.get(i);
            TypeName reducerArgType = TypeName.get(reducerArgs.get(i).asType());
            if (!creatorArgType.equals(reducerArgType)) {
                return false;
            }
        }
        return true;
    }

// 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/actioncreator/ActionCreatorElement.java
import com.google.auto.common.MoreElements;
import com.squareup.javapoet.TypeName;
import com.yheriatovych.reductor.annotations.ActionCreator;
import com.yheriatovych.reductor.processor.Env;
import com.yheriatovych.reductor.processor.ValidationException;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

package com.yheriatovych.reductor.processor.actioncreator;



public class ActionCreatorElement {
    public final List<ActionCreatorAction> actions;
    private final TypeElement typeElement;
    private Map<String, ActionCreatorAction> actionMap;

    private ActionCreatorElement(List<ActionCreatorAction> actions, TypeElement typeElement) {
        this.actions = actions;
        this.typeElement = typeElement;
        actionMap = new HashMap<>();
        for (ActionCreatorAction action : actions) {
            actionMap.put(action.actionType, action);
        }
    }

    public boolean hasAction(String actionType, List<? extends VariableElement> reducerArgs) {
        ActionCreatorAction actionCreator = actionMap.get(actionType);
        if (actionCreator == null || reducerArgs.size() != actionCreator.arguments.size()) return false;
        List<? extends VariableElement> arguments = actionCreator.arguments;
        for (int i = 0; i < arguments.size(); i++) {
            //we are doing black magic with checking if TypeName are equals
            //instead of checking if two TypeMirrors are equals because TypeMirrors can be different for the same type
            //happens when code is processed with several number of processing steps
            TypeName creatorArgType = actionCreator.argumentTypes.get(i);
            TypeName reducerArgType = TypeName.get(reducerArgs.get(i).asType());
            if (!creatorArgType.equals(reducerArgType)) {
                return false;
            }
        }
        return true;
    }

    public String getPackageName(Env env) {