package com.insightfullogic.lambdabehave.impl.specifications;

import com.insightfullogic.lambdabehave.impl.Specifier;
import com.insightfullogic.lambdabehave.specifications.ColumnDataSpecification;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class TitledTable<T, F, S> {
    private final List<Method> methods;
    private final Specifier specifier;
    private final Class clazz;

    private final List<F> firsts = new ArrayList<>();
    private final List<S> seconds = new ArrayList<>();

    public TitledTable(final List<Method> methods, final Specifier specifier, final Class clazz) {
        this.methods = methods;
        this.specifier = specifier;
        this.clazz = clazz;
    }

    public TitledTable<T, F, S> toShow(final String description, final ColumnDataSpecification<T> specification) {
        final Iterator<F> fit = firsts.iterator();
        final Iterator<S> sit = seconds.iterator();
        while (fit.hasNext()) {
            Object[] values = new Object[]{fit.next(), sit.next()};
            final T mock = (T) Enhancer.create(clazz, (MethodInterceptor) (o, method, objects, methodProxy) ->
                values[methods.indexOf(method)]);
            final String describe = String.format(description,
                    values[0], values[1],
                    methods.get(0).getName(), methods.get(1).getName());
            specifier.should(describe, expect -> specification.specifyBehaviour(expect, mock));
        }
        return this;
    }

    public TitledTable<T, F, S> withRow(final F first, final S second) {
        firsts.add(first);
        seconds.add(second);
        return this;
    }
}