/*
 * 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.test.JenaTestBase ;
import org.apache.jena.vocabulary.RDF ;
import org.junit.Assert;

public class TestStatementMethods extends AbstractModelTestBase
{

	protected Resource r;

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

	protected void checkChangedStatementSP( final Statement changed )
	{
		Assert.assertEquals(r, changed.getSubject());
		Assert.assertEquals(RDF.value, changed.getPredicate());
	}

	protected void checkCorrectStatements( final Statement sTrue,
			final Statement changed )
	{
		Assert.assertFalse(model.contains(sTrue));
		Assert.assertFalse(model.containsLiteral(r, RDF.value, true));
		Assert.assertTrue(model.contains(changed));
	}

	protected Statement loadInitialStatement()
	{
		final Statement sTrue = model
				.createLiteralStatement(r, RDF.value, true);
		model.add(sTrue);
		return sTrue;
	}

	@Override
	public void setUp()
	{
		super.setUp();
		r = model.createResource();
	}

	public void testAlt()
	{
		final Alt tvAlt = model.createAlt();
		Assert.assertEquals(tvAlt, model.createStatement(r, RDF.value, tvAlt)
				.getAlt());
	}

	public void testBag()
	{
		final Bag tvBag = model.createBag();
		Assert.assertEquals(tvBag, model.createStatement(r, RDF.value, tvBag)
				.getBag());
	}

	public void testBoolean()
	{
		final Statement s = model.createLiteralStatement(r, RDF.value, true);
		Assert.assertEquals(model.createTypedLiteral(true), s.getObject());
		Assert.assertEquals(true, s.getBoolean());
	}

	public void testByte()
	{
		final Statement s = model.createLiteralStatement(r, RDF.value,
				AbstractModelTestBase.tvByte);
		Assert.assertEquals(
				model.createTypedLiteral(AbstractModelTestBase.tvByte),
				s.getObject());
		Assert.assertEquals(AbstractModelTestBase.tvByte, s.getLong());
	}

	public void testChangeObjectBoolean()
	{
		final Statement sTrue = loadInitialStatement();
		final Statement sFalse = sTrue.changeLiteralObject(false);
		checkChangedStatementSP(sFalse);
		Assert.assertEquals(model.createTypedLiteral(false), sFalse.getObject());
		Assert.assertEquals(false, sFalse.getBoolean());
		checkCorrectStatements(sTrue, sFalse);
		Assert.assertTrue(model.containsLiteral(r, RDF.value, false));
	}

	public void testChangeObjectByte()
	{
		final Statement sTrue = loadInitialStatement();
		final Statement changed = sTrue
				.changeLiteralObject(AbstractModelTestBase.tvByte);
		checkChangedStatementSP(changed);
		Assert.assertEquals(
				model.createTypedLiteral(AbstractModelTestBase.tvByte),
				changed.getObject());
		Assert.assertEquals(AbstractModelTestBase.tvByte, changed.getByte());
		checkCorrectStatements(sTrue, changed);
		Assert.assertTrue(model.containsLiteral(r, RDF.value,
				AbstractModelTestBase.tvByte));
	}

	public void testChangeObjectChar()
	{
		final Statement sTrue = loadInitialStatement();
		final Statement changed = sTrue
				.changeLiteralObject(AbstractModelTestBase.tvChar);
		checkChangedStatementSP(changed);
		Assert.assertEquals(AbstractModelTestBase.tvChar, changed.getChar());
		Assert.assertEquals(
				model.createTypedLiteral(AbstractModelTestBase.tvChar),
				changed.getObject());
		checkCorrectStatements(sTrue, changed);
		Assert.assertTrue(model.containsLiteral(r, RDF.value,
				AbstractModelTestBase.tvChar));
	}

	public void testChangeObjectDouble()
	{
		final Statement sTrue = loadInitialStatement();
		final Statement changed = sTrue
				.changeLiteralObject(AbstractModelTestBase.tvDouble);
		checkChangedStatementSP(changed);
		Assert.assertEquals(
				model.createTypedLiteral(AbstractModelTestBase.tvDouble),
				changed.getObject());
		Assert.assertEquals(AbstractModelTestBase.tvDouble,
				changed.getDouble(), AbstractModelTestBase.dDelta);
		checkCorrectStatements(sTrue, changed);
		Assert.assertTrue(model.containsLiteral(r, RDF.value,
				AbstractModelTestBase.tvDouble));
	}

	public void testChangeObjectFloat()
	{
		final Statement sTrue = loadInitialStatement();
		final Statement changed = sTrue
				.changeLiteralObject(AbstractModelTestBase.tvFloat);
		checkChangedStatementSP(changed);
		Assert.assertEquals(
				model.createTypedLiteral(AbstractModelTestBase.tvFloat),
				changed.getObject());
		Assert.assertEquals(AbstractModelTestBase.tvFloat, changed.getFloat(),
				AbstractModelTestBase.fDelta);
		checkCorrectStatements(sTrue, changed);
		Assert.assertTrue(model.containsLiteral(r, RDF.value,
				AbstractModelTestBase.tvFloat));
	}

	public void testChangeObjectInt()
	{
		final Statement sTrue = loadInitialStatement();
		final Statement changed = sTrue
				.changeLiteralObject(AbstractModelTestBase.tvInt);
		checkChangedStatementSP(changed);
		Assert.assertEquals(
				model.createTypedLiteral(AbstractModelTestBase.tvInt),
				changed.getObject());
		Assert.assertEquals(AbstractModelTestBase.tvInt, changed.getInt());
		checkCorrectStatements(sTrue, changed);
		Assert.assertTrue(model.containsLiteral(r, RDF.value,
				AbstractModelTestBase.tvInt));
	}

	public void testChangeObjectLiteral()
	{
		final Statement sTrue = loadInitialStatement();
		model.remove(sTrue);
		Assert.assertFalse(model.contains(sTrue));
		Assert.assertFalse(model.containsLiteral(r, RDF.value, true));
	}

	// public void testResObj()
	// {
	// Resource tvResObj = model.createResource( new ResTestObjF() );
	// assertEquals( tvResObj, model.createStatement( r, RDF.value, tvResObj
	// ).getResource() );
	// }

	// public void testLitObj()
	// {
	// assertEquals( tvLitObj, model.createLiteralStatement( r, RDF.value,
	// tvLitObj ).getObject( new LitTestObjF() ) );
	// }

	public void testChangeObjectLong()
	{
		final Statement sTrue = loadInitialStatement();
		final Statement changed = sTrue
				.changeLiteralObject(AbstractModelTestBase.tvLong);
		checkChangedStatementSP(changed);
		Assert.assertEquals(
				model.createTypedLiteral(AbstractModelTestBase.tvLong),
				changed.getObject());
		Assert.assertEquals(AbstractModelTestBase.tvLong, changed.getLong());
		checkCorrectStatements(sTrue, changed);
		Assert.assertTrue(model.containsLiteral(r, RDF.value,
				AbstractModelTestBase.tvLong));
	}

	public void testChangeObjectShort()
	{
		final Statement sTrue = loadInitialStatement();
		final Statement changed = sTrue
				.changeLiteralObject(AbstractModelTestBase.tvShort);
		checkChangedStatementSP(changed);
		Assert.assertEquals(
				model.createTypedLiteral(AbstractModelTestBase.tvShort),
				changed.getObject());
		Assert.assertEquals(AbstractModelTestBase.tvShort, changed.getShort());
		checkCorrectStatements(sTrue, changed);
		Assert.assertTrue(model.containsLiteral(r, RDF.value,
				AbstractModelTestBase.tvShort));
	}

	public void testChangeObjectString()
	{
		final Statement sTrue = loadInitialStatement();
		final Statement changed = sTrue
				.changeObject(AbstractModelTestBase.tvString);
		checkChangedStatementSP(changed);
		Assert.assertEquals(AbstractModelTestBase.tvString, changed.getString());
		checkCorrectStatements(sTrue, changed);
		Assert.assertTrue(model.contains(r, RDF.value,
				AbstractModelTestBase.tvString));
	}

	public void testChangeObjectStringWithLanguage()
	{
		final String lang = "en";
		final Statement sTrue = loadInitialStatement();
		final Statement changed = sTrue.changeObject(
				AbstractModelTestBase.tvString, lang);
		checkChangedStatementSP(changed);
		Assert.assertEquals(AbstractModelTestBase.tvString, changed.getString());
		Assert.assertEquals(lang, changed.getLanguage());
		checkCorrectStatements(sTrue, changed);
		Assert.assertTrue(model.contains(r, RDF.value,
				AbstractModelTestBase.tvString, lang));
	}

	public void testChangeObjectYByte()
	{
		final Statement sTrue = loadInitialStatement();
		final Statement changed = sTrue
				.changeLiteralObject(AbstractModelTestBase.tvByte);
		checkChangedStatementSP(changed);
		Assert.assertEquals(AbstractModelTestBase.tvByte, changed.getByte());
		checkCorrectStatements(sTrue, changed);
		Assert.assertTrue(model.containsLiteral(r, RDF.value,
				AbstractModelTestBase.tvByte));
	}

	public void testChar()
	{
		final Statement s = model.createLiteralStatement(r, RDF.value,
				AbstractModelTestBase.tvChar);
		Assert.assertEquals(
				model.createTypedLiteral(AbstractModelTestBase.tvChar),
				s.getObject());
		Assert.assertEquals(AbstractModelTestBase.tvChar, s.getChar());
	}

	public void testDouble()
	{
		final Statement s = model.createLiteralStatement(r, RDF.value,
				AbstractModelTestBase.tvDouble);
		Assert.assertEquals(
				model.createTypedLiteral(AbstractModelTestBase.tvDouble),
				s.getObject());
		Assert.assertEquals(AbstractModelTestBase.tvDouble, s.getDouble(),
				AbstractModelTestBase.dDelta);
	}

	public void testFloat()
	{
		final Statement s = model.createLiteralStatement(r, RDF.value,
				AbstractModelTestBase.tvFloat);
		Assert.assertEquals(
				model.createTypedLiteral(AbstractModelTestBase.tvFloat),
				s.getObject());
		Assert.assertEquals(AbstractModelTestBase.tvFloat, s.getFloat(),
				AbstractModelTestBase.fDelta);
	}

	public void testGetLiteralFailure()
	{
		try
		{
			model.createStatement(r, RDF.value, r).getLiteral();
			Assert.fail("should trap non-literal object");
		}
		catch (final LiteralRequiredException e)
		{
			JenaTestBase.pass();
		}
	}

	public void testGetResource()
	{
		Assert.assertEquals(r, model.createStatement(r, RDF.value, r)
				.getResource());
	}

	public void testGetResourceFailure()
	{
		try
		{
			model.createLiteralStatement(r, RDF.value, false).getResource();
			Assert.fail("should trap non-resource object");
		}
		catch (final ResourceRequiredException e)
		{
			JenaTestBase.pass();
		}
	}

	public void testGetTrueBoolean()
	{
		Assert.assertEquals(true,
				model.createLiteralStatement(r, RDF.value, true).getLiteral()
						.getBoolean());
	}

	public void testInt()
	{
		final Statement s = model.createLiteralStatement(r, RDF.value,
				AbstractModelTestBase.tvInt);
		Assert.assertEquals(
				model.createTypedLiteral(AbstractModelTestBase.tvInt),
				s.getObject());
		Assert.assertEquals(AbstractModelTestBase.tvInt, s.getInt());
	}

	// public void testChangeObjectResObject()
	// {
	// Resource tvResObj = model.createResource( new ResTestObjF() );
	// Statement sTrue = loadInitialStatement();
	// Statement changed = sTrue.changeObject( tvResObj );
	// checkChangedStatementSP( changed );
	// assertEquals( tvResObj, changed.getResource() );
	// checkCorrectStatements( sTrue, changed );
	// assertTrue( model.contains( r, RDF.value, tvResObj ) );
	// }

	public void testLong()
	{
		final Statement s = model.createLiteralStatement(r, RDF.value,
				AbstractModelTestBase.tvLong);
		Assert.assertEquals(
				model.createTypedLiteral(AbstractModelTestBase.tvLong),
				s.getObject());
		Assert.assertEquals(AbstractModelTestBase.tvLong, s.getLong());
	}

	public void testSeq()
	{
		final Seq tvSeq = model.createSeq();
		Assert.assertEquals(tvSeq, model.createStatement(r, RDF.value, tvSeq)
				.getSeq());
	}

	public void testShort()
	{
		final Statement s = model.createLiteralStatement(r, RDF.value,
				AbstractModelTestBase.tvShort);
		Assert.assertEquals(
				model.createTypedLiteral(AbstractModelTestBase.tvShort),
				s.getObject());
		Assert.assertEquals(AbstractModelTestBase.tvShort, s.getShort());
	}

	public void testString()
	{
		Assert.assertEquals(AbstractModelTestBase.tvString, model
				.createStatement(r, RDF.value, AbstractModelTestBase.tvString)
				.getString());
	}

	public void testStringWithLanguage()
	{
		final String lang = "fr";
		Assert.assertEquals(
				AbstractModelTestBase.tvString,
				model.createStatement(r, RDF.value,
						AbstractModelTestBase.tvString, lang).getString());
		Assert.assertEquals(
				lang,
				model.createStatement(r, RDF.value,
						AbstractModelTestBase.tvString, lang).getLanguage());
	}
}
