/*
 * Copyright (c) 2008 Kasper Nielsen.
 *
 * 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 cake.internal.errorhandling;

import static java.util.Objects.requireNonNull;

import org.cakeframework.container.Component;
import org.cakeframework.errorhandling.ErrorBuilder;

import cake.internal.util.mirror.AnnotationOnErrorReflectionData;
import cake.internal.util.mirror.MirrorOfClass;

/**
 * An error handler for a component. Non-root components that does not define error handler method them self can reuse
 * their parents error handler.
 */
public class ComponentErrorHandler {

    /** The component that defines the error handlers. */
    private final Component component;

    // If we follow through with no need to use reflection if you do not want to
    private final AnnotationOnErrorReflectionData[] methods;

    /** The parent error handler, is null for the root components error handler. */
    private final ComponentErrorHandler parent;

    private ComponentErrorHandler(ComponentErrorHandler parent, Component owner, AnnotationOnErrorReflectionData[] methods) {
        this.parent = parent;
        this.component = requireNonNull(owner);
        this.methods = requireNonNull(methods);
    }

    /**
     * Returns the component that defines this error handler.
     *
     * @return the component that defines this error handler
     */
    public Component getComponent() {
        return component;
    }

    public ErrorBuilder raiseError(Component component, String id) {
        return new InternalErrorBuilder(this, component, id);
    }

    // TODO if we have mixins that define the error handler.
    public static ComponentErrorHandler create(ComponentErrorHandler parent, Component component, MirrorOfClass<?> mirror) {

        if (!component.getPath().toString().equals("/")
                && (mirror.methods().annotatedMethods() == null || mirror.methods().annotatedMethods().onErrorMethods() == null)) {
            return parent;
        }

        return new ComponentErrorHandler(parent, component,
                mirror.methods().annotatedMethods() == null ? new AnnotationOnErrorReflectionData[0] : mirror.methods().annotatedMethods().onErrorMethods());
    }

    static void process(ComponentErrorHandler h, InternalOnErrorContext context) {
        ComponentErrorHandler handler = h;
        while (handler.parent != null) {
            // boolean matchFirst = handler.methods[0].matches(context.id(), context.getCause());
            if (handler.methods.length > 1) {
                throw new UnsupportedOperationException();
            }
            // if (matchFirst != null) {
            // // Technically, this can be a Mixin
            // method.invoke(handler.owner.getInstance(), context);
            // }
            handler = handler.parent;
        }
        System.out.println("Default Error");
    }

}
