/*******************************************************************************
*   Copyright 2014 Analog Devices, Inc.
*
*   Licensed 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 com.analog.lyric.dimple.test.matlabproxy;

import static org.junit.Assert.*;

import org.junit.Test;

import com.analog.lyric.dimple.matlabproxy.PDiscreteDomain;
import com.analog.lyric.dimple.matlabproxy.PDomain;
import com.analog.lyric.dimple.matlabproxy.PHelpers;
import com.analog.lyric.dimple.matlabproxy.PRealDomain;
import com.analog.lyric.dimple.matlabproxy.PRealJointDomain;
import com.analog.lyric.dimple.model.domains.DiscreteDomain;
import com.analog.lyric.dimple.model.domains.Domain;
import com.analog.lyric.dimple.model.domains.RealDomain;
import com.analog.lyric.dimple.model.domains.RealJointDomain;
import com.analog.lyric.dimple.test.DimpleTestBase;

public class TestPDomain extends DimpleTestBase
{

	@Test
	public void test()
	{
		DiscreteDomain abc = DiscreteDomain.create('a','b','c');
		PDiscreteDomain pabc = new PDiscreteDomain(abc);
		assertInvariants(pabc);
		assertSame(abc, pabc.getModelerObject());
		
		PDomain pabc2 = PHelpers.wrapDomain(abc);
		assertInvariants(pabc2);
		assertTrue(pabc2.isDiscrete());
		assertSame(abc, pabc2.getModelerObject());
		
		RealDomain r = new RealDomain(1.23, 3.1415);
		PRealDomain pr = new PRealDomain(r);
		assertInvariants(pr);
		assertSame(r, pr.getModelerObject());
		
		RealDomain r2 = RealDomain.unbounded();
		assertInvariants(new PRealDomain(r2));
		
		PDomain pr2 = PHelpers.wrapDomain(r2);
		assertInvariants(pr2);
		assertTrue(pr2.isReal());
		assertSame(r2, pr2.getModelerObject());
		
		RealDomain r3 = new RealDomain(0.0, 1.0);
		Object pr3 = new PRealDomain(r3);
		assertInvariants((PDomain)pr3);
		assertEquals(pr3, new PRealDomain(r3));
		assertEquals(pr3, new PRealDomain(new RealDomain(0.0, 1.0)));
		assertNotEquals(pr3, new PRealDomain(new RealDomain(0.0, 2.0)));
		assertNotEquals(pr3, pabc2);
		assertNotEquals(pr3, r3);
		assertEquals(pr3.hashCode(), new PRealDomain(r3).hashCode());
		
		RealJointDomain rj = RealJointDomain.create(r, r2, r3);
		PRealJointDomain prj = new PRealJointDomain(rj);
		assertInvariants(prj);
		assertSame(rj, prj.getModelerObject());
		
		PDomain prj2 = PHelpers.wrapDomain(rj);
		assertInvariants(prj2);
		assertSame(rj, prj2.getModelerObject());
		
		Object[] prs = new Object[] {pr, pr2, pr3};
		PRealJointDomain prj3 = new PRealJointDomain(prs);
		assertInvariants(prj3);
		assertEquals(prs.length, prj3.getNumVars());
		
		for (int i = 0; i < prs.length; ++i)
		{
			RealDomain expected = ((PRealDomain)prs[i]).getModelerObject();
			RealDomain actual = prj3.getModelerObject().getRealDomains()[i];
			assertEquals(expected, actual);
		}
	}

	static public void assertInvariants(PDomain pdomain)
	{
		TestPObject.assertInvariants(pdomain);
		Domain mdomain = pdomain.getModelerObject();
		assertSame(mdomain, pdomain.getDelegate());
		assertEquals(pdomain,pdomain);
		assertNotNull(mdomain);
		assertEquals(pdomain.isDiscrete(), mdomain.isDiscrete());
		assertEquals(pdomain.isJoint(), mdomain.isRealJoint());
		assertEquals(pdomain.isReal(), mdomain.isReal());
		
		if (pdomain.isDiscrete())
		{
			assertDiscreteInvariants((PDiscreteDomain)pdomain);
		}
		if (pdomain.isJoint())
		{
			assertRealJointInvariants((PRealJointDomain)pdomain);
		}
		if (pdomain.isReal())
		{
			assertRealInvariants((PRealDomain)pdomain);
		}
	}
	
	static private void assertDiscreteInvariants(PDiscreteDomain pdiscrete)
	{
		DiscreteDomain mdiscrete = pdiscrete.getModelerObject();
		assertArrayEquals(mdiscrete.getElements(), pdiscrete.getElements());
	}
	
	static private void assertRealInvariants(PRealDomain preal)
	{
		RealDomain mreal = preal.getModelerObject();
		assertEquals(mreal.getUpperBound(), preal.getUpperBound(), 0.0);
		assertEquals(mreal.getLowerBound(), preal.getLowerBound(), 0.0);
	}
	
	static private void assertRealJointInvariants(PRealJointDomain pjoint)
	{
		RealJointDomain mjoint = pjoint.getModelerObject();
		assertEquals(mjoint.getNumVars(), pjoint.getNumVars());
	}
}
