/* XBN Java: Generically useful, non-GUI Java code. http://sourceforge.net/projects/xbnjava Copyright (C) 1997-2003, Jeff Epstein All rights reserved. Modifications: No Redistribution in binary form, with or without modifications, are permitted provided that the following conditions are met: * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * If modifications are made to source code then this license should indicate that fact in the "Modifications" section above. * Neither the author, nor the contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [NOTE: This license contains NO advertising clause.] */ package xbn.array; import xbn.XBNObject; import xbn.array.primitive.PrimitiveArray; /**

Compare the values in two PrimitiveArrays. See PrimitiveArray.

Source code:  CompareArrays.java

@version 0.9b @author Jeff Epstein, http://sourceforge.net/projects/xbnjava. **/ public class CompareArrays extends XBNObject { private CAConfig cac = null; private boolean bAssumePARqdValid = false; private boolean bAssumePAActlValid = false; /**

Create a CompareArrays with default settings.

Equal to CompareArrays(new CAConfig())

**/ public CompareArrays() { this(new CAConfig()); } /**

Create a CompareArrays.

@param ca_config Defines the rules used when comparing the two PrimitiveArrays. May not be null. See getCAConfig. **/ public CompareArrays(CAConfig ca_config) { throwAXIfNull(ca_config, "ca_config", sCNSTR); cac = ca_config; } /**

Get the CAConfig for direct maniplation.

@return ca_config Exactly as provided to the constructor. **/ public CAConfig getCAConfig() { return cac; } /**

Declare if it should be assumed (by hasRqdValues) that both the required and actual PrimitiveArrays are (individually) valid and ready for comparison. See hasRqdValues and PrimitiveArray.wasValidated.

Get with doAssumePAsValid.

hasRqdValues expects that both pa_rqd.wasValidated() and pa_actual.wasValidated() equal true and pa_rqd.getPrimitiveArrayRule().getPARDupNullLen().areDupsOk(), pa_rqd.getPrimitiveArrayRule().getPARDupNullLen().isNullOk() and pa_actual.getPrimitiveArrayRule().getPARDupNullLen().isNullOk() all equal false.

If pa_actual and pa_rqd are both definitely valid--you knew this before you even created the PrimitiveArrays--then don't waste time validating them. Just call this function with "true", and the hasRqdValues function will just assume that the above requirements have been met, without checking. Understand you will get unpredictable results if you use this function but shouldn't.

This function first calls setAssumePARqdValid(b_assumePAsValid) and then setAssumePAActlValid(b_assumePAsValid)

**/ public final void setAssumePAsValid(boolean b_assumePAsValid) { setAssumePARqdValid(b_assumePAsValid); setAssumePAActlValid(b_assumePAsValid); } /**

Should it be assumed (by hasRqdValues) that both the required and actual PrimitiveArrays are (individually) valid and ready for comparison?

Set with setAssumePAsValid.

@return (doAssumePARqdValid() && doAssumePAActlValid()) **/ public final boolean doAssumePAsValid() { return (doAssumePARqdValid() && doAssumePAActlValid()); } /**

Declare if it should be assumed (by hasRqdValues) that the required PrimitiveArray is (individually) valid and ready for comparison. See setAssumePAsValid for information.

Get with doAssumePARqdValid.

@param b_assumePARqdValid Should hasRqdValues assume that the required PrimitiveArray is individually valid? If true, yes. If false, no. **/ public final void setAssumePARqdValid(boolean b_assumePARqdValid) { bAssumePARqdValid = b_assumePARqdValid; } /**

Should it be assumed (by hasRqdValues) that the required PrimitiveArray is (individually) valid and ready for comparison?

@return b_assumePARqdValid Exactly as provided to setAssumePARqdValid **/ public final boolean doAssumePARqdValid() { return bAssumePARqdValid; } /**

Declare if it should be assumed (by hasRqdValues) that the actual PrimitiveArray is (individually) valid and ready for comparison. See setAssumePAsValid for information.

Get with doAssumePARqdValid.

@param b_assumePARqdValid Should hasRqdValues assume that the required PrimitiveArray is individually valid? If true, yes. If false, no. **/ public final void setAssumePAActlValid(boolean b_assumePAActlValid) { bAssumePAActlValid = b_assumePAActlValid; } /**

Should it be assumed (by hasRqdValues) that the actual PrimitiveArray is (individually) valid and ready for comparison?

@return b_assumePAActlValid Exactly as provided to setAssumePAActlValid **/ public final boolean doAssumePAActlValid() { return bAssumePAActlValid; } /**

Are the actual values legal, according to both the rules in CAConfig and the "required" values?

Equal to hasRqdValues(null, null, null, pa_rqd, pa_actual)

**/ public boolean hasRqdValues(PrimitiveArray pa_rqd, PrimitiveArray pa_actual) { return hasRqdValues(null, null, null, pa_rqd, pa_actual); } /**

Are the actual values legal, according to both the rules in CAConfig and the "required" values?

@param s_callingClsFnc The fully-qualified name of the class-dot-function for use in potential error messages only. This is the place where the error message should appear that it was generated from. For example: xbn.array.CompareArrays.hasRqdValues. If any of s_callingClsFnc, s_rqdName, or s_actualName are non-null, when this function would normally return false, it will instead throw an AssertException, with a descriptive error message. @param s_rqdName The descriptive name of pa_rqd, for potential error messages only. @param s_actualName The descriptive name of pa_actual, for potential error messages only. @param pa_rqd The required values. May not be null, nor a different type than pa_actual. @param pa_actual The actual values to analyze and validate. May not be null, nor a different type than pa_rqd. @return true pa_actual has required valuse, as determined by the rules in the CAConfig and pa_rqd.
false If pa_actual does not have values as required. **/ public boolean hasRqdValues(String s_callingClsFnc, String s_rqdName, String s_actualName, PrimitiveArray pa_rqd, PrimitiveArray pa_actual) { final String sPRNC_PRN = ") ("; throwAXIfNull(pa_rqd, "pa_rqd", "hasRqdValues"); throwAXIfNull(pa_actual, "pa_actual", "hasRqdValues"); boolean bAXIfBad = (s_callingClsFnc != null || s_actualName != null); if(!doAssumePARqdValid()) { if(!pa_rqd.wasValidated()) { throwAX("hasRqdValues: Both doAssumePARqdValid() and pa_rqd.wasValidated() equal false."); } if(pa_rqd.getPrimitiveArrayRule().getPARDupNullLen().areDupsOk() || pa_rqd.getPrimitiveArrayRule().getPARDupNullLen().isNullOk()) { throwAX("hasRqdValues: doAssumePARqdValid() is false but either pa_rqd.getPrimitiveArrayRule().getPARDupNullLen().areDupsOk() (" + pa_rqd.getPrimitiveArrayRule().getPARDupNullLen().areDupsOk() + ") or pa_rqd.getPrimitiveArrayRule().getPARDupNullLen().isNullOk() (" + pa_rqd.getPrimitiveArrayRule().getPARDupNullLen().isNullOk() + ") are true."); } } //The required PrimitiveArray is (individually) valid, and //ready for comparison. if(!doAssumePAActlValid()) { if(!pa_actual.wasValidated()) { throwAX("hasRqdValues: Both doAssumePAActlValid() and pa_actual.wasValidated() equal false."); } if(pa_actual.getPrimitiveArrayRule().getPARDupNullLen().isNullOk()) { throwAX("hasRqdValues: doAssumePAActlValid() is false but pa_actual.getPrimitiveArrayRule().getPARDupNullLen().isNullOk() is true."); } } //The actual PrimitiveArray is individually valid, and ready for comparison. int iLengthR = pa_rqd.getLength(); int iLengthA = pa_actual.getLength(); boolean bExtraOk = getCAConfig().isExtraOk(); boolean bMissingOk = getCAConfig().isMissingOk(); if(iLengthR > iLengthA && !bMissingOk) { if(bAXIfBad) { throwAXBad(s_callingClsFnc, s_actualName, pa_rqd, pa_actual, "pa_rqd.getLength() equals " + iLengthR + ", which is different than pa_actual.getLength() (" + iLengthA + "). Since missing is *not* okay, the length of pa_actual must equal or exceed pa_rqd."); } return false; } if(iLengthR < 1) { //There are zero required values. No matter what exists/ //does not exist in pa_actual is fine. If extra were not //allowed, we'd have already exited the function by now. return true; } try { if(getCAConfig().isOrderingRqd()) { //Ordering is only applicable when the lengths of both are equal. //This condition is verified in CAConfig, in the constructor, by //the b_orderingRqd parameter only allowed to be true when both //b_missingOk and b_extraOk are also true. int j = 0; if(!getCAConfig().getOrderDirSameOpp()) { //Ordering of pa_actual must be opposite as pa_rqd. j = (iLengthR - 1); } for(int i = 0; i < iLengthR; i++) { if(!pa_rqd.areLmntsEqual(i, pa_actual, j)) { if(bAXIfBad) { String sOpp = sES; if(!getCAConfig().getOrderDirSameOpp()) { sOpp = " NOTE: The opposite of array index " + i + " is [pa_rqd.getLength() - 1 - " + i + "], or " + j + "]"; } throwAXBad(s_callingClsFnc, s_actualName, pa_rqd, pa_actual, "pa_rqd.getString(" + i + sPRNC_PRN + pa_rqd.getString(i) + ") is not equal to pa_actual.getString(" + i + sPRNC_PRN + pa_actual.getString(i) + ")." + sOpp); } return false; } if(getCAConfig().getOrderDirSameOpp()) { //Ordering must be the same as pa_rqd. j++; } else { j--; } } //pa_actual is exactly as it needs to be. return true; } //ordering is (a) not required or (b) it *is* required, //but the lengths of required and actual are different. // //If (b) ignore the ordering requirement, and just check that...xxx if(!bMissingOk) { boolean bFound = false; int i = 0; for(; i < iLengthR; i++) { bFound = false; for(int j = 0; j < iLengthA; j++) { if(pa_rqd.areLmntsEqual(i, pa_actual, j)) { bFound = true; break; } } if(!bFound) { if(bAXIfBad) { throwAXBad(s_callingClsFnc, s_actualName, pa_rqd, pa_actual, "getCAConfig().isMissingOk() equals false, but pa_rqd.getString(" + i + sPRNC_PRN + pa_rqd.getString(i) + ") does not exist in pa_actual."); } return false; } } } if(!bExtraOk) { boolean bFound = false; int i = 0; for(; i < iLengthA; i++) { bFound = false; for(int j = 0; j < iLengthR; j++) { if(pa_actual.areLmntsEqual(i, pa_rqd, j)) { bFound = true; break; } } if(!bFound) { if(bAXIfBad) { throwAXBad(s_callingClsFnc, s_actualName, pa_rqd, pa_actual, "getCAConfig().isExtraOk() equals false, but pa_actual.getString(" + i + sPRNC_PRN + pa_actual.getString(i) + ") does not exist in pa_rqd."); } return false; } } } } catch(ClassCastException ccx) { throwAX("pa_rqd (" + pa_rqd.getClass().getName() + ") and pa_actual (" + pa_actual.getClass().getName() + ") are different types."); } //We've made it this far? Holy crap! return true; } /**

If the actual values are illegal crash with an explanation. Otherwise do nothing.

Equal to crashIfBadValues("xbn.array.CompareArrays.crashIfBadValues", "pa_rqd" ,"pa_actual", pa_rqd, pa_actual)

**/ public void crashIfBadValues(PrimitiveArray pa_rqd, PrimitiveArray pa_actual) { crashIfBadValues("xbn.array.CompareArrays.crashIfBadValues", "pa_rqd" ,"pa_actual", pa_rqd, pa_actual); } /**

If the actual values are illegal crash with an explanation. Otherwise do nothing.

Equal to hasRqdValues("xbn.array.CompareArrays.crashIfBadValues", "pa_rqd" ,"pa_actual", pa_rqd, pa_actual) (supressing the return value)

Before calling hasRqdValues, all string parameters are analyzed to ensure they are non-null and at least one character in length.

**/ public void crashIfBadValues(String s_callingClsFnc, String s_rqdName, String s_actualName, PrimitiveArray pa_rqd, PrimitiveArray pa_actual) { throwAXIfBadStr(s_callingClsFnc, "s_callingClsFnc", "crashIfBadValues"); throwAXIfBadStr(s_rqdName, "s_rqdName", "crashIfBadValues"); throwAXIfBadStr(s_actualName, "s_actualName", "crashIfBadValues"); boolean bUNRTRND = hasRqdValues(s_callingClsFnc, s_rqdName, s_actualName, pa_rqd, pa_actual); } /**

Used internally, by hasRqdValues. See the code for hasRqdValues.

**/ protected void throwAXBad(String s_callingClsFnc, String s_actualName, PrimitiveArray pa_rqd, PrimitiveArray pa_actual, String s_currently) { final String sQT = "'"; throwAX(s_callingClsFnc + ": '" + s_actualName + "' does not have required values, as required by [" + getCAConfig().toString() + "] where pa_rqd is [" + pa_rqd.getList(sQT, "', '", sQT) + "]. Values that *do* exist in pa_actual: [" + pa_actual.getList(sQT, "', '", sQT) + "]. Currently, " + s_currently); } }