/*
 * 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.jorphan.gui;

import static java.lang.String.format;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;

import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.function.ObjIntConsumer;
import java.util.function.ToIntFunction;

import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;

/**
 * Listener implementation that stores {@link TableModelEvent} and can make assertions against them.
 */
public class TableModelEventBacker implements TableModelListener {

    /**
     * Makes assertions for a single {@link TableModelEvent}.
     */
    public class EventAssertion {
        private List<ObjIntConsumer<TableModelEvent>> assertions = new ArrayList<>();

        /**
         * Adds an assertion first args is table model event, second one is event index.
         * @return <code>this</code>
         */
        public EventAssertion add(ObjIntConsumer<TableModelEvent> assertion) {
            assertions.add(assertion);
            return this;
        }

        /**
         * Adds assertion based on a {@link ToIntFunction to-int} transformation (examples: <code>TableModelEvent::getType</code>).
         * @param name Label for assertion reason
         * @param expected Expected value.
         * @param f {@link ToIntFunction to-int} transformation (examples: <code>TableModelEvent::getType</code>).
         * @return <code>this</code>
         */
        public EventAssertion addInt(String name, int expected, ToIntFunction<TableModelEvent> f) {
            return add((e,i) -> assertEquals(format("%s[%d]", name, i), expected, f.applyAsInt(e)));
        }

        /**
         * Adds {@link TableModelEvent#getSource()} assertion.
         * @return <code>this</code>
         */
        public EventAssertion source(Object expected) {
            return add((e,i) -> assertSame(format("source[%d]",i), expected, e.getSource()));
        }

        /**
         * Adds {@link TableModelEvent#getType()} assertion.
         * @return <code>this</code>
         */
        public EventAssertion type(int expected) {
            return addInt("type", expected, TableModelEvent::getType);
        }

        /**
         * Adds {@link TableModelEvent#getColumn()} assertion.
         * @return <code>this</code>
         */
        public EventAssertion column(int expected) {
            return addInt("column", expected, TableModelEvent::getColumn);
        }

        /**
         * Adds {@link TableModelEvent#getFirstRow()} assertion.
         * @return <code>this</code>
         */
        public EventAssertion firstRow(int expected) {
            return addInt("firstRow", expected, TableModelEvent::getFirstRow);
        }

        /**
         * Adds {@link TableModelEvent#getLastRow()} assertion.
         * @return <code>this</code>
         */
        public EventAssertion lastRow(int expected) {
            return addInt("lastRow", expected, TableModelEvent::getLastRow);
        }

        /**
         * Check assertion against provided value.
         * @param event Event to check
         * @param index Index.
         */
        protected void assertEvent(TableModelEvent event, int index) {
            assertions.forEach(a -> a.accept(event, index));
        }
    }

    private Deque<TableModelEvent> events = new LinkedList<>();

    /**
     * Stores event.
     */
    @Override
    public void tableChanged(TableModelEvent e) {
        events.add(e);
    }

    public Deque<TableModelEvent> getEvents() {
        return events;
    }

    /**
     * Creates a new event assertion.
     * @see #assertEvents(EventAssertion...)
     */
    public EventAssertion assertEvent() {
        return new EventAssertion();
    }

    /**
     * Checks each event assertion against each backed event in order. Event storage is cleared after it.
     */
    public void assertEvents(EventAssertion... assertions) {
        try {
            assertEquals("event count", assertions.length, events.size());

            int i = 0;
            for (TableModelEvent event : events) {
                assertions[i].assertEvent(event, i++);
            }
        } finally {
            events.clear();
        }
    }


}

@@ -1704,24 +1704,69 @@
 vent index.%0A
+         * @param assertion assertion to add%0A
          * @
@@ -1782,32 +1782,32 @@
 ode%3Ethis%3C/code%3E%0A
-
          */%0A    
@@ -2636,32 +2636,109 @@
 e()%7D assertion.%0A
+         * @param expected Object to compare against the source of the event%0A
          * @retu
@@ -2996,32 +2996,100 @@
 e()%7D assertion.%0A
+         * @param expected int value of the type to compare against%0A
          * @retu
@@ -3321,32 +3321,102 @@
 n()%7D assertion.%0A
+         * @param expected int value of the column to compare against%0A
          * @retu
@@ -3656,32 +3656,111 @@
 w()%7D assertion.%0A
+         * @param expected int value of the first row that should have changed%0A
          * @retu
@@ -4005,32 +4005,110 @@
 w()%7D assertion.%0A
+         * @param expected int value of the last row that should have changed%0A
          * @retu
@@ -4892,24 +4892,78 @@
  assertion.%0A
+     * @return a newly created %7B@link EventAssertion%7D%0A
      * @see 
@@ -5089,32 +5089,32 @@
 %0A    %7D%0A%0A    /**%0A
-
      * Checks ea
@@ -5203,16 +5203,90 @@
 ter it.%0A
+     * @param assertions a collection if %7B@link EventAssertion%7Ds to check%0A
      */%0A

javadoc add missing tags.