/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common
 * Development and Distribution License("CDDL") (collectively, the
 * "License"). You may not use this file except in compliance with the
 * License. You can obtain a copy of the License at
 * http://www.netbeans.org/cddl-gplv2.html
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 * specific language governing permissions and limitations under the
 * License.  When distributing the software, include this License Header
 * Notice in each file and include the License file at
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the GPL Version 2 section of the License file that
 * accompanied this code. If applicable, add the following below the
 * License Header, with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Contributor(s):
 *
 * The Original Software is NetBeans. The Initial Developer of the Original
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 * Microsystems, Inc. All Rights Reserved.
 *
 * If you wish your version of this file to be governed by only the CDDL
 * or only the GPL Version 2, indicate your decision by adding
 * "[Contributor] elects to include this software in this distribution
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 * single choice of license, a recipient has the option to distribute
 * your version of this file under either the CDDL, the GPL Version 2 or
 * to extend the choice of license to its licensees as provided above.
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 * Version 2 license, then the option applies only if the new code is
 * made subject to such option by the copyright holder.
 */
package org.netbeans.validation.api;

import java.awt.EventQueue;
import java.lang.reflect.InvocationTargetException;
import org.junit.Test;
import org.netbeans.validation.api.ui.ValidationGroup;
import org.netbeans.validation.api.ui.ValidationListener;
import org.netbeans.validation.api.ui.ValidationUI;
import static org.junit.Assert.*;

/**
 *
 * @author Tim Boudreau
 */
public class MergeTest {
    @Test
    public void testSanity() {
        assertTrue(true);
        try {
            EventQueue.invokeAndWait(new Runnable() {

                public void run() {
                    doTestSanity();
                }
            });
        } catch (InterruptedException ex) {
            ex.printStackTrace();
            fail(ex.getMessage());
        } catch (InvocationTargetException ex) {
            ex.printStackTrace();
            fail(ex.getMessage());
        }
    }

    @Test
    public void testMergeGroups() {
        assertTrue(true);
        try {
            EventQueue.invokeAndWait(new Runnable() {

                public void run() {
                    doTestMergeGroups();
                }
            });
        } catch (InterruptedException ex) {
            ex.printStackTrace();
            fail(ex.getMessage());
        } catch (InvocationTargetException ex) {
            ex.printStackTrace();
            fail(ex.getMessage());
        }
    }

    @Test
    public void testRemovedGroupsDontGetTheirUIsTriggered() {
        assertTrue(true);
        try {
            EventQueue.invokeAndWait(new Runnable() {

                public void run() {
                    doTestRemovedGroupsDontGetTheirUIsTriggered();
                }

            });
        } catch (InterruptedException ex) {
            ex.printStackTrace();
            fail(ex.getMessage());
        } catch (InvocationTargetException ex) {
            ex.printStackTrace();
            fail(ex.getMessage());
        }
    }

    private void doTestRemovedGroupsDontGetTheirUIsTriggered() {
        VL vlA = new VL();
        VL vlB = new VL();
        VL vlC = new VL();

        UI uiA = new UI(1);
        UI uiB = new UI(2);
        UI uiC = new UI(3);

        ValidationGroup a = ValidationGroup.create(uiA);
        ValidationGroup b = ValidationGroup.create(uiB);
        ValidationGroup c = ValidationGroup.create(uiC);

        a.addValidationGroup(b, true);
        b.addValidationGroup(c, true);

        a.add (vlA);
        b.add (vlB);
        c.add (vlC);

        vlA.setText ("fail");
        uiA.assertProblem("fail");
        uiB.assertProblem("fail");
        uiC.assertProblem("fail");

        vlA.setText ("pass");
        uiA.assertCleared();
        uiB.assertCleared();
        uiC.assertCleared();

        b.removeValidationGroup(c);
        vlA.setText ("fail");
        uiA.assertProblem("fail");
        uiB.assertProblem("fail");
        uiC.assertNotProblem();

        uiC.cleared = false;
        uiC.p = null;
        vlA.setText ("pass");
        uiA.assertCleared();
        uiA.assertNotProblem();
        uiB.assertCleared();
        uiB.assertNotProblem();
        uiC.assertNotCleared();

        vlB.setText ("fail");
        uiC.assertNotProblem();
        uiC.assertNotCleared();
        uiB.assertProblem("fail");
        uiA.assertProblem("fail");    
    }

    private void doTestSanity() {
        UI ui = new UI(1);
        ValidationGroup g = ValidationGroup.create(ui);
        VL vl = new VL();
        g.add(vl);
        g.addUI(ui);
        
        vl.setText ("fail");
        vl.assertValidated();
        vl.assertFailed();
        ui.assertProblem("fail");

        vl.setText ("pass");
        vl.assertValidated();
        vl.assertPassed();
        ui.assertCleared();
    }

    private void doTestMergeUIs() {
        UI ui1 = new UI(1);
        UI ui2 = new UI(2);
        UI ui3 = new UI(3);
        ValidationGroup g = ValidationGroup.create(ui1);
        g.addUI(ui1);
        g.addUI(ui2);
        g.addUI(ui3);
        VL vl = new VL();
        g.add(vl);
        
        vl.setText ("pass");
        ui1.assertCleared();
        ui2.assertCleared();
        ui3.assertCleared();
        vl.setText("fail");
        ui1.assertProblem("fail");
        ui2.assertProblem("fail");
        ui3.assertProblem("fail");
        g.removeUI(ui3);

        ui3.setProblem(new Problem("fail", Severity.FATAL));
        ui3.cleared = false;

        vl.setText("pass");
        ui1.assertCleared();
        ui2.assertCleared();
        ui3.assertNotCleared();

        ui3.clearProblem();
        vl.setText("fail");
        ui1.assertProblem("fail");
        ui2.assertProblem("fail");
        ui3.assertNotProblem();
        g.removeUI(ui2);
        g.addUI(ui3);
        vl.setText("fail");
        ui3.assertProblem("fail");
    }

    private void doTestMergeGroups() {
        VL vlA = new VL();
        VL vlB = new VL();
        VL vlC = new VL();

        UI uiA = new UI(1);
        UI uiB = new UI(2);
        UI uiC = new UI(3);

        ValidationGroup a = ValidationGroup.create(uiA);
        ValidationGroup b = ValidationGroup.create(uiB);
        ValidationGroup c = ValidationGroup.create(uiC);

        a.addValidationGroup(b, true);
        b.addValidationGroup(c, true);

        a.add (vlA);
        b.add (vlB);
        c.add (vlC);

        vlA.setText ("pass");
        uiA.assertCleared();
        uiB.assertCleared();
        uiC.assertCleared();

        vlA.setText("fail");
        uiA.assertProblem("fail");
        uiB.assertProblem("fail");
        uiC.assertProblem("fail");
        uiA.assertNotCleared();
        uiB.assertNotCleared();
        uiC.assertNotCleared();

        vlA.setText ("pass");
        vlB.setText ("pass");
        uiA.assertCleared();
        uiB.assertCleared();
        uiC.assertCleared();

        vlB.setText("fail");
        uiA.assertProblem("fail");
        uiB.assertProblem("fail");
        uiC.assertProblem("fail");

        vlB.setText ("pass");
        vlC.setText ("pass");
        uiA.assertCleared();
        uiB.assertCleared();
        uiC.assertCleared();

        vlC.setText("fail");
        uiA.assertProblem("fail");
        uiB.assertProblem("fail");
        uiC.assertProblem("fail");

        vlA.setText ("pass");
        vlB.setText ("pass");
        vlC.setText ("pass");
        uiA.assertCleared();
        uiB.assertCleared();
        uiC.assertCleared();

        b.removeValidationGroup(c);
        vlA.setText ("pass");
        uiA.assertCleared();
        uiB.assertCleared();
        uiC.assertNotCleared();

        uiC.cleared = false;
        uiB.cleared = false;
        uiA.cleared = false;
        uiC.p = null;
        uiA.p = null;
        uiB.p = null;
        uiC.assertNotProblem();

        vlB.setText ("fail");
        uiC.assertNotProblem();
        uiC.assertNotCleared();
        uiB.assertProblem("fail");
        uiA.assertProblem("fail");

        vlC.setText ("pass");
        uiA.assertNotCleared();
        uiB.assertNotCleared();
        uiC.assertCleared();

        vlA.txt = "pass";
        vlB.txt = "pass";
        vlC.txt = "pass";

        a.addValidationGroup(c, true);
        vlA.setText ("pass");
        uiB.assertCleared();
        uiC.assertCleared();
        uiA.assertCleared();

        vlA.setText("fail");
        uiA.assertProblem("fail");
        uiB.assertProblem("fail");
        uiC.assertProblem("fail");
        vlA.setText ("pass");
        vlB.setText ("pass");
        vlC.setText ("pass");

        vlB.setText ("pass");
        uiA.assertCleared();
        uiB.assertCleared();
        uiC.assertCleared();

        vlB.setText("fail");
        uiA.assertProblem("fail");
        uiB.assertProblem("fail");
        uiC.assertProblem("fail");
        vlA.setText ("pass");
        vlB.setText ("pass");
        vlC.setText ("pass");

        vlC.setText ("pass");
        uiA.assertCleared();
        uiB.assertCleared();
        uiC.assertCleared();

        vlC.setText("fail");
        uiA.assertProblem("fail");
        uiB.assertProblem("fail");
        uiC.assertProblem("fail");

    }

    private class UI implements ValidationUI {
        private final int val;
        UI (int val) {
            this.val = val;
        }

        Problem p;
        boolean cleared;

        public void assertCleared() {
            boolean old = cleared;
            cleared = false;
            assertTrue(old);
        }

        public void assertNotCleared() {
            assertFalse (cleared);
        }

        public void assertProblem(String msg) {
            assertNotNull(p);
            assertEquals(msg, p.getMessage());
            cleared = false;
        }

        public void clearProblem() {
            System.err.println(this + " clearProblem");
            cleared = true;
            p = null;
        }

        public void setProblem(Problem problem) {
            System.err.println(this + " setProblem " + problem);
            p = problem;
        }

        public void assertNotProblem() {
            assertNull (p);
        }

        @Override
        public String toString() {
            return "UI" + val;
        }
    }

    private static class VL extends ValidationListener {

        private boolean validated;
        private boolean passed;
        final V v = new V();
        private String txt = "pass";

        void assertValidated() {
            boolean old = validated;
            validated = false;
            assertTrue(old);
        }

        void assertPassed() {
            boolean old = passed;
            passed = false;
            assertTrue(old);
        }

        void assertNotValidated() {
            boolean old = validated;
            validated = false;
            assertFalse(old);
        }

        void assertFailed() {
            boolean old = passed;
            passed = false;
            assertFalse(old);
        }

        public boolean validate(Problems problems, String compName, String model) {
            validated = true;
            boolean result = true;
            if (!"pass".equals(model)) {
                problems.add(model);
                result = false;
            }
            passed = result;
            return result;
        }

        public void setText(String txt) {
            this.txt = txt;
            validate();
        }

        @Override
        protected boolean validate(Problems problems) {
            return v.validate(problems, txt, txt);
        }

        private class V implements Validator<String> {

            public boolean validate(Problems problems, String compName, String model) {
                return VL.this.validate(problems, compName, model);
            }
        }
    }
}
