/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you 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 org.apache.isis.core.metamodel.methods;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.isis.commons.internal.collections._Lists;
import org.apache.isis.commons.internal.collections._Sets;
import org.apache.isis.core.metamodel.facetapi.FacetHolder;
import org.apache.isis.core.metamodel.facets.ImperativeFacet;
import org.apache.isis.core.metamodel.spec.ObjectSpecification;
import org.apache.isis.core.metamodel.specloader.specimpl.ObjectSpecificationAbstract;
import org.apache.isis.core.metamodel.specloader.validator.MetaModelVisitingValidatorAbstract;
import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;

import lombok.NonNull;
import lombok.val;

/**
 * 
 * @since 2.0
 *
 */
public class OrphanedSupportingMethodValidator 
extends MetaModelVisitingValidatorAbstract {
    
    @Override
    public boolean isEnabled() {
        //return !getConfiguration().getApplib().getAnnotation().getAction().isExplicit();
        return true; 
    }
    
    @Override
    public void validate(@NonNull ObjectSpecification spec) {
            
        if(!(spec instanceof ObjectSpecificationAbstract)) {
            return; // continue
        }

        if(spec.getCorrespondingClass().getName().equals("org.apache.isis.testdomain.model.bad.InvalidOrphanedActionSupport")) {
            System.err.println("!!! BINGO");
        }
        
        val potentialOrphans = ((ObjectSpecificationAbstract) spec).getPotentialOrphans();
        if(potentialOrphans.isEmpty()) {
            return; // continue
        }

        // methods known to the meta-model
        val recognizedMethods = spec.streamFacetHolders()
                .flatMap(FacetHolder::streamFacets)
                .filter(ImperativeFacet.class::isInstance)
                .map(ImperativeFacet.class::cast)
                .map(ImperativeFacet::getMethods)
                .flatMap(List::stream)
                .collect(Collectors.toCollection(HashSet::new));

        // methods intended to be included with the meta-model but missing
        val notRecognizedMethods =
                _Sets.minus(potentialOrphans, recognizedMethods);

        // find reasons why these are not recognized    
        notRecognizedMethods.forEach(notRecognizedMethod->{
            
            val unmetContraints = unmetContraints(spec, notRecognizedMethod);

            val messageFormat = "%s#%s: is assumed to support "
                    + "a property, collection or action. Unmet constraint(s): %s";
            
            ValidationFailure.raiseFormatted(
                    spec,
                    String.format(
                            messageFormat,
                            spec.getIdentifier().getClassName(),
                            notRecognizedMethod.getName(),
                            unmetContraints.stream()
                            .collect(Collectors.joining("; "))));
        });

        potentialOrphans.clear(); // no longer needed  

    }

    // -- VALIDATION LOGIC

    private List<String> unmetContraints(
            ObjectSpecification spec,
            Method method) {

        val unmetContraints = _Lists.<String>newArrayList();

        unmetContraints.add("unsupported method signature or "
                + "orphaned (not associated with a member)");
        return unmetContraints;

    }





}

@@ -1752,539 +1752,175 @@
 lic 
-boolean isEnabled() %7B%0A        //return !getConfiguration().getApplib().getAnnotation().getAction().isExplicit();%0A        return true; %0A    %7D%0A    %0A    @Override%0A    public void validate(@NonNull ObjectSpecification spec) %7B%0A            %0A        if(!(spec instanceof ObjectSpecificationAbstract)) %7B%0A            return; // continue%0A        %7D%0A%0A        if(spec.getCorrespondingClass().getName().equals(%22org.apache.isis.testdomain.model.bad.InvalidOrphanedActionSupport%22)) %7B%0A            System.err.println(%22!!! BINGO%22);%0A        %7D%0A        
+void validate(@NonNull ObjectSpecification spec) %7B%0A            %0A        if(!(spec instanceof ObjectSpecificationAbstract)) %7B%0A            return; // continue%0A        %7D%0A
 %0A   

remove debug lines