/*
 * 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.jena.rdf.model.test;

import org.apache.jena.rdf.model.*;
import org.apache.jena.rdf.model.test.helpers.TestingModelFactory;
import org.apache.jena.vocabulary.RDF;
import org.junit.Assert;

public class TestIterators extends AbstractModelTestBase {
    int num = 5;
    Resource subject[] = new Resource[num];
    Property predicate[] = new Property[num];
    Statement stmts[] = new Statement[num * num];

    String suri = "http://aldabaran/test6/s";
    String puri = "http://aldabaran/test6/";

    public TestIterators(final TestingModelFactory modelFactory, final String name) {
        super(modelFactory, name);
    }

    @Override
    public void setUp() {
        super.setUp();

        for ( int i = 0 ; i < num ; i++ ) {
            subject[i] = model.createResource(suri + Integer.toString(i));
            predicate[i] = model.createProperty(puri + Integer.toString(i), "p");
        }

        for ( int i = 0 ; i < num ; i++ ) {
            for ( int j = 0 ; j < num ; j++ ) {
                final Statement stmt = model.createStatement(subject[i], predicate[j], model.createTypedLiteral((i * num) + j));
                model.add(stmt);
                model.add(stmt);
                stmts[(i * num) + j] = stmt;
            }
        }
    }

    /**
     * bug detected in StatementIteratorImpl - next does not advance current, so
     * remove doesn't work with next; this test should expose the bug.
     */
    public void testIteratorRemove() {
        final StmtIterator it = model.listStatements();
        try {
            while (it.hasNext()) {
                it.next();
                it.remove();
            }
            Assert.assertEquals("Remove failed", 0, model.size());
        } catch (UnsupportedOperationException ex) {
            throw ex;
        } finally {
            it.close();
        }

    }

    public void testListObjects() {
        int count = 0;
        NodeIterator iter;
        iter = model.listObjects();
        while (iter.hasNext()) {
            iter.nextNode();
            count++;
        }
        Assert.assertEquals(num * num, count);
    }

    public void testNamespaceIterator() {
        final boolean predf[] = new boolean[num];
        for ( int i = 0 ; i < num ; i++ ) {
            predf[i] = false;
        }
        final NsIterator nIter = model.listNameSpaces();
        while (nIter.hasNext()) {
            final String ns = nIter.nextNs();
            boolean found = false;
            for ( int i = 0 ; i < num ; i++ ) {
                if ( ns.equals(predicate[i].getNameSpace()) ) {
                    found = true;
                    Assert.assertFalse("Should not have found " + predicate[i] + " already.", predf[i]);
                    predf[i] = true;
                }
            }
            Assert.assertTrue("Should have found " + ns, found);
        }
        for ( int i = 0 ; i < num ; i++ ) {
            Assert.assertTrue("Should have found " + predicate[i], predf[i]);
        }
    }

    public void testObjectsOfProperty() {

        NodeIterator iter;
        final boolean[] object = new boolean[num * num];
        for ( int i = 0 ; i < (num * num) ; i++ ) {
            object[i] = false;
        }
        iter = model.listObjectsOfProperty(predicate[0]);
        while (iter.hasNext()) {
            final Literal l = (Literal)iter.nextNode();
            final int i = l.getInt();
            object[i] = true;
        }
        for ( int i = 0 ; i < (num * num) ; i++ ) {
            if ( (i % num) == 0 ) {
                Assert.assertTrue(object[i]);
            } else {
                Assert.assertFalse(object[i]);
            }
        }

    }

    public void testObjectsOfPropertyAndValue() {
        NodeIterator iter;
        final boolean[] object = new boolean[num];
        final Resource subj = model.createResource();
        for ( int i = 0 ; i < num ; i++ ) {
            model.addLiteral(subj, RDF.value, i);
            object[i] = false;
        }

        iter = model.listObjectsOfProperty(subj, RDF.value);
        while (iter.hasNext()) {
            final int i = ((Literal)iter.nextNode()).getInt();
            object[i] = true;
        }
        for ( int i = 0 ; i < (num) ; i++ ) {
            Assert.assertTrue(object[i]);
        }
    }

    public void testResourceIterator() {

        final boolean subjf[] = new boolean[num];

        for ( int i = 0 ; i < num ; i++ ) {
            subjf[i] = false;
        }

        boolean found = false;
        final ResIterator rIter = model.listSubjects();
        while (rIter.hasNext()) {
            final Resource subj = rIter.nextResource();
            found = false;
            for ( int i = 0 ; i < num ; i++ ) {
                if ( subj.equals(subject[i]) ) {
                    found = true;
                    Assert.assertFalse("Should not have found " + subject[i] + " already.", subjf[i]);
                    subjf[i] = true;
                }
            }
            Assert.assertTrue("Should have found " + subj, found);
        }
        for ( int i = 0 ; i < num ; i++ ) {
            Assert.assertTrue("Should have found " + subject[i], subjf[i]);
        }

        // System.err.println(
        // "WARNING: listNameSpace testing wonky for the moment" );
        // NsIterator nIter = model.listNameSpaces();
        // HashSet fromIterator = new HashSet();
        // HashSet fromPredicates = new HashSet();
        // while (nIter.hasNext()) fromIterator.add( nIter.next() );
        // for (int i = 0; i < num; i += 1) fromPredicates.add(
        // predicate[i].getNameSpace() );
        // if (fromIterator.equals( fromPredicates ))
        // {}
        // else
        // {
        // System.err.println( "| oh dear." );
        // System.err.println( "| predicate namespaces: " + fromPredicates );
        // System.err.println( "| iterator namespaces: " + fromIterator );
        // }

    }

    public void testStatementIter() {
        final int numStmts = num * num;
        final boolean stmtf[] = new boolean[numStmts];
        Assert.assertEquals(numStmts, model.size());
        for ( int i = 0 ; i < numStmts ; i++ ) {
            stmtf[i] = false;
        }

        final StmtIterator sIter = model.listStatements();
        while (sIter.hasNext()) {
            final Statement stmt = sIter.nextStatement();
            boolean found = false;
            for ( int i = 0 ; i < numStmts ; i++ ) {
                if ( stmt.equals(stmts[i]) ) {
                    found = true;
                    Assert.assertFalse("Should not have found " + stmts[i] + " already.", stmtf[i]);
                    stmtf[i] = true;
                }
            }
            Assert.assertTrue("Should have found " + stmt, found);
        }
        for ( int i = 0 ; i < numStmts ; i++ ) {
            Assert.assertTrue("Should have found " + stmts[i], stmtf[i]);
        }
    }
    // SEE the tests in model.test: TestReifiedStatements and
    // TestStatementResources
    // {
    // System.err.println(
    // "WARNING: reification testing suppressed for the moment" );
    // /* Reification is not working properly
    //
    // for (int i=0; i<num; i++) {
    // stmtf[i] = false;
    // model.add(stmts[i], predicate[i], i);
    // }
    // sIter = model.listReifiedStatements();
    // while (sIter.hasNext()) {
    // Statement stmt = sIter.next();
    // found = false;
    // for (int i=0; i<num; i++) {
    // if (stmt.equals(stmts[i])) {
    // found = true;
    // if (stmtf[i]) error(test, 200);
    // stmtf[i] = true;
    // }
    // }
    // if (! found) error(test, 210);
    // }
    // for (int i=0; i<num; i++) {
    // if (! stmtf[i]) error(test, 220+i);
    // } */
    // }
}
