/**************************************************************
 * 
 * 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.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"

#include <tools/debug.hxx>

#include "scmatrix.hxx"
#include "global.hxx"
#include "address.hxx"
#include "formula/errorcodes.hxx"
#include "interpre.hxx"
#include <svl/zforlist.hxx>
#include <tools/stream.hxx>
#include <rtl/math.hxx>

#include <math.h>

//------------------------------------------------------------------------

void ScMatrix::CreateMatrix(SCSIZE nC, SCSIZE nR)		// nur fuer ctor
{
    pErrorInterpreter = NULL;
	nColCount = nC;
	nRowCount = nR;
	SCSIZE nCount = nColCount * nRowCount;
	if ( !nCount || nCount > GetElementsMax() )
	{
		DBG_ERRORFILE("ScMatrix::CreateMatrix: dimension error");
		nColCount = nRowCount = 1;
		pMat = new ScMatrixValue[1];
        pMat[0].fVal = CreateDoubleError( errStackOverflow);
	}
	else
		pMat = new ScMatrixValue[nCount];
	mnValType = NULL;
    mnNonValue = 0;
}

void ScMatrix::Clear()
{
    DeleteIsString();
    delete [] pMat;
}

ScMatrix::~ScMatrix()
{
    Clear();
}

ScMatrix* ScMatrix::Clone() const
{
    ScMatrix* pScMat = new ScMatrix( nColCount, nRowCount);
	MatCopy(*pScMat);
    pScMat->SetErrorInterpreter( pErrorInterpreter);    // TODO: really?
	return pScMat;
}

ScMatrix* ScMatrix::CloneIfConst()
{
    return (mbCloneIfConst || IsEternalRef()) ? Clone() : this;
}

void ScMatrix::Resize( SCSIZE nC, SCSIZE nR)
{
    Clear();
    CreateMatrix(nC, nR);
}

ScMatrix* ScMatrix::CloneAndExtend( SCSIZE nNewCols, SCSIZE nNewRows ) const
{
    ScMatrix* pScMat = new ScMatrix( nNewCols, nNewRows);
    MatCopy(*pScMat);
    pScMat->SetErrorInterpreter( pErrorInterpreter); 
    return pScMat;
}

void ScMatrix::SetErrorAtInterpreter( sal_uInt16 nError ) const
{
    if ( pErrorInterpreter )
        pErrorInterpreter->SetError( nError);
}

//
//	File format: sal_uInt16 columns, sal_uInt16 rows, (columns*rows) entries:
//	sal_uInt8 type ( CELLTYPE_NONE, CELLTYPE_VALUE, CELLTYPE_STRING ); nothing, double or String
//

ScMatrix::ScMatrix(SvStream& /* rStream */)
        : pErrorInterpreter( NULL)
        , nRefCnt(0)
{
#if SC_ROWLIMIT_STREAM_ACCESS 
#error address types changed!
	sal_uInt16 nC;
	sal_uInt16 nR;

	rStream >> nC;
	rStream >> nR;

	CreateMatrix(nC, nR);
	DBG_ASSERT( pMat, "pMat == NULL" );

	String aMatStr;
	double fVal;
	rtl_TextEncoding eCharSet = rStream.GetStreamCharSet();
	SCSIZE nCount = nColCount * nRowCount;
	SCSIZE nReadCount = (SCSIZE) nC * nR;
	for (SCSIZE i=0; i<nReadCount; i++)
	{
		sal_uInt8 nType;
		rStream >> nType;
		if ( nType == CELLTYPE_VALUE )
		{
			if ( i < nCount )
				rStream >> pMat[i].fVal;
			else
				rStream >> fVal;
		}
		else
		{
			// For unknown types read and forget string (upwards compatibility)

			if ( nType != CELLTYPE_NONE )
				rStream.ReadByteString( aMatStr, eCharSet );

			if ( i < nCount )
			{
				if (!mnValType)
					ResetIsString();		// init string flags
				mnValType[i] = ( nType == CELLTYPE_NONE ? SC_MATVAL_EMPTY : SC_MATVAL_STRING );
                mnNonValue++;

				if ( nType == CELLTYPE_STRING )
					pMat[i].pS = new String(aMatStr);
				else
					pMat[i].pS = NULL;
			}
		}
	}
#else
	CreateMatrix(0,0);
#endif // SC_ROWLIMIT_STREAM_ACCESS
}

void ScMatrix::Store(SvStream& /* rStream */) const
{
#if SC_ROWLIMIT_STREAM_ACCESS 
#error address types changed!
	SCSIZE nCount = nColCount * nRowCount;
	// Don't store matrix with more than sal_uInt16 max elements, old versions
	// might get confused in loops for(sal_uInt16 i=0; i<nC*nR; i++)
	if ( !pMat || nCount > ((sal_uInt16)(~0)) )
	{
		DBG_ASSERT( pMat, "ScMatrix::Store: pMat == NULL" );
		// We can't store a 0 dimension because old versions rely on some
		// matrix being present, e.g. DDE link results, and old versions didn't
		// create a matrix if dimension was 0. Store an error result.
		rStream << (sal_uInt16) 1;
		rStream << (sal_uInt16) 1;
		rStream << (sal_uInt8) CELLTYPE_VALUE;
		double fVal;
		::rtl::math::setNan( &fVal );
		rStream << fVal;
		return;
	}

	rStream << (sal_uInt16) nColCount;
#if SC_ROWLIMIT_MORE_THAN_32K
    #error row32k
#endif
	rStream << (sal_uInt16) nRowCount;

	String aMatStr;
	rtl_TextEncoding eCharSet = rStream.GetStreamCharSet();
	for (SCSIZE i=0; i<nCount; i++)
	{
		sal_uInt8 nType = CELLTYPE_VALUE;
		if ( mnValType && IsNonValueType( mnValType[i]))
		{
			if ( pMat[i].pS )
				aMatStr = *pMat[i].pS;
			else
				aMatStr.Erase();

			if ( mnValType[i] == SC_MATVAL_STRING )
				nType = CELLTYPE_STRING;
			else
				nType = CELLTYPE_NONE;
		}
		rStream << nType;
		if ( nType == CELLTYPE_VALUE )
			rStream << pMat[i].fVal;
		else if ( nType == CELLTYPE_STRING )
			rStream.WriteByteString( aMatStr, eCharSet );
	}
#endif // SC_ROWLIMIT_STREAM_ACCESS
}

void ScMatrix::ResetIsString()
{
	SCSIZE nCount = nColCount * nRowCount;
	if (mnValType)
	{
		for (SCSIZE i = 0; i < nCount; i++)
		{
			if ( IsNonValueType( mnValType[i]))
				delete pMat[i].pS;
		}
	}
	else
		mnValType = new sal_uInt8[nCount];
	memset( mnValType, 0, nCount * sizeof( sal_uInt8 ) );
    mnNonValue = 0;
}

void ScMatrix::DeleteIsString()
{
	if ( mnValType )
	{
		SCSIZE nCount = nColCount * nRowCount;
		for ( SCSIZE i = 0; i < nCount; i++ )
		{
			if (IsNonValueType( mnValType[i]))
				delete pMat[i].pS;
		}
		delete [] mnValType;
		mnValType = NULL;
        mnNonValue = 0;
	}
}

void ScMatrix::PutDouble(double fVal, SCSIZE nC, SCSIZE nR)
{
	if (ValidColRow( nC, nR))
		PutDouble( fVal, CalcOffset( nC, nR) );
	else
	{
		DBG_ERRORFILE("ScMatrix::PutDouble: dimension error");
	}
}

void ScMatrix::PutString(const String& rStr, SCSIZE nC, SCSIZE nR)
{
	if (ValidColRow( nC, nR))
		PutString( rStr, CalcOffset( nC, nR) );
	else
	{
		DBG_ERRORFILE("ScMatrix::PutString: dimension error");
	}
}

void ScMatrix::PutString(const String& rStr, SCSIZE nIndex)
{
	if (mnValType == NULL)
		ResetIsString();
	if ( IsNonValueType( mnValType[nIndex]) && pMat[nIndex].pS )
		*(pMat[nIndex].pS) = rStr;
	else
    {
		pMat[nIndex].pS = new String(rStr);
        mnNonValue++;
    }
	mnValType[nIndex] = SC_MATVAL_STRING;
}

void ScMatrix::PutStringEntry( const String* pStr, sal_uInt8 bFlag, SCSIZE nIndex )
{
	DBG_ASSERT( bFlag, "ScMatrix::PutStringEntry: bFlag == 0" );
	if (mnValType == NULL)
		ResetIsString();
    // Make sure all bytes of the union are initialized to be able to access
    // the value with if (IsValueOrEmpty()) GetDouble(). Backup pS first.
    String* pS = pMat[nIndex].pS;
    pMat[nIndex].fVal = 0.0;
    // An EMPTY or EMPTYPATH entry must not have a string pointer therefor.
    DBG_ASSERT( (((bFlag & SC_MATVAL_EMPTY) == SC_MATVAL_EMPTY) && !pStr) || sal_True,
            "ScMatrix::PutStringEntry: pStr passed through EMPTY entry");
	if ( IsNonValueType( mnValType[nIndex]) && pS )
	{
        if ((bFlag & SC_MATVAL_EMPTY) == SC_MATVAL_EMPTY)
            delete pS, pS = NULL;
		if ( pStr )
            *pS = *pStr;
		else if (pS)
            pS->Erase();
        pMat[nIndex].pS = pS;
	}
	else
    {
		pMat[nIndex].pS = (pStr ? new String(*pStr) : NULL);
        mnNonValue++;
    }
	mnValType[nIndex] = bFlag;
}

void ScMatrix::PutEmpty(SCSIZE nC, SCSIZE nR)
{
	if (ValidColRow( nC, nR))
		PutEmpty( CalcOffset( nC, nR) );
	else
	{
		DBG_ERRORFILE("ScMatrix::PutEmpty: dimension error");
	}
}

void ScMatrix::PutEmpty(SCSIZE nIndex)
{
	if (mnValType == NULL)
		ResetIsString();
	if ( IsNonValueType( mnValType[nIndex]) && pMat[nIndex].pS )
    {
		delete pMat[nIndex].pS;
    }
    else
    {
        mnNonValue++;
    }
	mnValType[nIndex] = SC_MATVAL_EMPTY;
	pMat[nIndex].pS = NULL;
	pMat[nIndex].fVal = 0.0;
}

void ScMatrix::PutEmptyPath(SCSIZE nC, SCSIZE nR)
{
    if (ValidColRow( nC, nR))
        PutEmptyPath( CalcOffset( nC, nR) );
    else
    {
        DBG_ERRORFILE("ScMatrix::PutEmptyPath: dimension error");
    }
}

void ScMatrix::PutEmptyPath(SCSIZE nIndex)
{
    if (mnValType == NULL)
        ResetIsString();
    if ( IsNonValueType( mnValType[nIndex]) && pMat[nIndex].pS )
    {
        delete pMat[nIndex].pS;
    }
    else
    {
        mnNonValue++;
    }
    mnValType[nIndex] = SC_MATVAL_EMPTYPATH;
    pMat[nIndex].pS = NULL;
    pMat[nIndex].fVal = 0.0;
}

void ScMatrix::PutBoolean(bool bVal, SCSIZE nC, SCSIZE nR)
{
	if (ValidColRow( nC, nR))
		PutBoolean( bVal, CalcOffset( nC, nR) );
	else
	{
		DBG_ERRORFILE("ScMatrix::PutBoolean: dimension error");
	}
}

void ScMatrix::PutBoolean( bool bVal, SCSIZE nIndex)
{
    if (mnValType == NULL)
        ResetIsString();
    if ( IsNonValueType( mnValType[nIndex]) && pMat[nIndex].pS )
    {
        delete pMat[nIndex].pS;
        mnNonValue--;
    }

    mnValType[nIndex] = SC_MATVAL_BOOLEAN;
    pMat[nIndex].pS = NULL;
    pMat[nIndex].fVal = bVal ? 1. : 0.;
}

sal_uInt16 ScMatrix::GetError( SCSIZE nC, SCSIZE nR) const
{
    if (ValidColRowOrReplicated( nC, nR ))
        return GetError( CalcOffset( nC, nR) );
    else
    {
        DBG_ERRORFILE("ScMatrix::GetError: dimension error");
		return errNoValue;
    }
}

double ScMatrix::GetDouble(SCSIZE nC, SCSIZE nR) const
{
    if (ValidColRowOrReplicated( nC, nR ))
		return GetDouble( CalcOffset( nC, nR) );
	else
	{
		DBG_ERRORFILE("ScMatrix::GetDouble: dimension error");
		return CreateDoubleError( errNoValue);
	}
}

const String& ScMatrix::GetString(SCSIZE nC, SCSIZE nR) const
{
    if (ValidColRowOrReplicated( nC, nR ))
	{
		SCSIZE nIndex = CalcOffset( nC, nR);
		if ( IsString( nIndex ) )
			return GetString( nIndex );
		else
        {
            SetErrorAtInterpreter( GetError( nIndex));
			DBG_ERRORFILE("ScMatrix::GetString: access error, no string");
        }
	}
	else
	{
		DBG_ERRORFILE("ScMatrix::GetString: dimension error");
	}
	return ScGlobal::GetEmptyString();
}


String ScMatrix::GetString( SvNumberFormatter& rFormatter, SCSIZE nIndex) const
{
    if (IsString( nIndex))
    {
        if (IsEmptyPath( nIndex))
        {   // result of empty sal_False jump path
            sal_uLong nKey = rFormatter.GetStandardFormat( NUMBERFORMAT_LOGICAL,
                    ScGlobal::eLnge);
            String aStr;
            Color* pColor = NULL;
            rFormatter.GetOutputString( 0.0, nKey, aStr, &pColor);
            return aStr;
        }
        return GetString( nIndex );
    }

    sal_uInt16 nError = GetError( nIndex);
    if (nError)
    {
        SetErrorAtInterpreter( nError);
        return ScGlobal::GetErrorString( nError);
    }

    double fVal= GetDouble( nIndex);
    sal_uLong nKey = rFormatter.GetStandardFormat( NUMBERFORMAT_NUMBER,
            ScGlobal::eLnge);
    String aStr;
    rFormatter.GetInputLineString( fVal, nKey, aStr);
    return aStr;
}


String ScMatrix::GetString( SvNumberFormatter& rFormatter, SCSIZE nC, SCSIZE nR) const
{
    if (ValidColRowOrReplicated( nC, nR ))
    {
        SCSIZE nIndex = CalcOffset( nC, nR);
        return GetString( rFormatter, nIndex);
    }
    else
    {
        DBG_ERRORFILE("ScMatrix::GetString: dimension error");
    }
    return String();
}


const ScMatrixValue* ScMatrix::Get(SCSIZE nC, SCSIZE nR, ScMatValType& nType) const
{
    if (ValidColRowOrReplicated( nC, nR ))
	{
		SCSIZE nIndex = CalcOffset( nC, nR);
		if (mnValType)
			nType = mnValType[nIndex];
		else
			nType = SC_MATVAL_VALUE;
		return &pMat[nIndex];
	}
	else
	{
		DBG_ERRORFILE("ScMatrix::Get: dimension error");
	}
    nType = SC_MATVAL_EMPTY;
	return NULL;
}

void ScMatrix::MatCopy(ScMatrix& mRes) const
{
    if (nColCount > mRes.nColCount || nRowCount > mRes.nRowCount)
	{
		DBG_ERRORFILE("ScMatrix::MatCopy: dimension error");
	}
    else if ( nColCount == mRes.nColCount && nRowCount == mRes.nRowCount )
	{
		if (mnValType)
		{
            ScMatValType nType;
			mRes.ResetIsString();
			for (SCSIZE i = 0; i < nColCount; i++)
			{
				SCSIZE nStart = i * nRowCount;
				for (SCSIZE j = 0; j < nRowCount; j++)
				{
					if (IsNonValueType( (nType = mnValType[nStart+j])))
						mRes.PutStringEntry( pMat[nStart+j].pS, nType, nStart+j );
					else
                    {
                        mRes.pMat[nStart+j].fVal = pMat[nStart+j].fVal;
                        mRes.mnValType[nStart+j] = nType;
                    }
				}
			}
		}
		else
		{
			mRes.DeleteIsString();
			SCSIZE nCount = nColCount * nRowCount;
			for (SCSIZE i = 0; i < nCount; i++)
				mRes.pMat[i].fVal = pMat[i].fVal;
		}
	}
    else
    {
        // Copy this matrix to upper left rectangle of result matrix.
        if (mnValType)
        {
            ScMatValType nType;
            mRes.ResetIsString();
            for (SCSIZE i = 0; i < nColCount; i++)
            {
                SCSIZE nStart = i * nRowCount;
                SCSIZE nResStart = i * mRes.nRowCount;
                for (SCSIZE j = 0; j < nRowCount; j++)
                {
                    if (IsNonValueType( (nType = mnValType[nStart+j])))
                        mRes.PutStringEntry( pMat[nStart+j].pS, nType, nResStart+j );
                    else
                    {
                        mRes.pMat[nResStart+j].fVal = pMat[nStart+j].fVal;
                        mRes.mnValType[nResStart+j] = nType;
                    }
                }
            }
        }
        else
        {
            mRes.DeleteIsString();
            for (SCSIZE i = 0; i < nColCount; i++)
            {
                SCSIZE nStart = i * nRowCount;
                SCSIZE nResStart = i * mRes.nRowCount;
                for (SCSIZE j = 0; j < nRowCount; j++)
                    mRes.pMat[nResStart+j].fVal = pMat[nStart+j].fVal;
            }
        }
    }
}

void ScMatrix::MatTrans(ScMatrix& mRes) const
{
	if (nColCount != mRes.nRowCount || nRowCount != mRes.nColCount)
	{
		DBG_ERRORFILE("ScMatrix::MatTrans: dimension error");
	}
	else
	{
		if (mnValType)
		{
            ScMatValType nType;
			mRes.ResetIsString();
			for ( SCSIZE i = 0; i < nColCount; i++ )
			{
				SCSIZE nStart = i * nRowCount;
				for ( SCSIZE j = 0; j < nRowCount; j++ )
				{
					if (IsNonValueType( (nType = mnValType[nStart+j])))
						mRes.PutStringEntry( pMat[nStart+j].pS, nType, j*mRes.nRowCount+i );
					else
                    {
						mRes.pMat[j*mRes.nRowCount+i].fVal = pMat[nStart+j].fVal;
						mRes.mnValType[j*mRes.nRowCount+i] = nType;
                    }
				}
			}
		}
		else
		{
			mRes.DeleteIsString();
			for ( SCSIZE i = 0; i < nColCount; i++ )
			{
				SCSIZE nStart = i * nRowCount;
				for ( SCSIZE j = 0; j < nRowCount; j++ )
				{
					mRes.pMat[j*mRes.nRowCount+i].fVal = pMat[nStart+j].fVal;
				}
			}
		}
	}
}

//UNUSED2009-05 void ScMatrix::MatCopyUpperLeft(ScMatrix& mRes) const
//UNUSED2009-05 {
//UNUSED2009-05     if (nColCount < mRes.nColCount || nRowCount < mRes.nRowCount)
//UNUSED2009-05     {
//UNUSED2009-05         DBG_ERRORFILE("ScMatrix::MatCopyUpperLeft: dimension error");
//UNUSED2009-05     }
//UNUSED2009-05     else
//UNUSED2009-05     {
//UNUSED2009-05         if (mnValType)
//UNUSED2009-05         {
//UNUSED2009-05             ScMatValType nType;
//UNUSED2009-05             mRes.ResetIsString();
//UNUSED2009-05             for ( SCSIZE i = 0; i < mRes.nColCount; i++ )
//UNUSED2009-05             {
//UNUSED2009-05                 SCSIZE nStart = i * nRowCount;
//UNUSED2009-05                 for ( SCSIZE j = 0; j < mRes.nRowCount; j++ )
//UNUSED2009-05                 {
//UNUSED2009-05                     if ( IsNonValueType( (nType = mnValType[nStart+j]) ))
//UNUSED2009-05                         mRes.PutStringEntry( pMat[nStart+j].pS, nType,
//UNUSED2009-05                             i*mRes.nRowCount+j );
//UNUSED2009-05                     else
//UNUSED2009-05                     {
//UNUSED2009-05                         mRes.pMat[i*mRes.nRowCount+j].fVal = pMat[nStart+j].fVal;
//UNUSED2009-05                         mRes.mnValType[i*mRes.nRowCount+j] = nType;
//UNUSED2009-05                     }
//UNUSED2009-05                 }
//UNUSED2009-05             }
//UNUSED2009-05         }
//UNUSED2009-05         else
//UNUSED2009-05         {
//UNUSED2009-05             mRes.DeleteIsString();
//UNUSED2009-05             for ( SCSIZE i = 0; i < mRes.nColCount; i++ )
//UNUSED2009-05             {
//UNUSED2009-05                 SCSIZE nStart = i * nRowCount;
//UNUSED2009-05                 for ( SCSIZE j = 0; j < mRes.nRowCount; j++ )
//UNUSED2009-05                 {
//UNUSED2009-05                     mRes.pMat[i*mRes.nRowCount+j].fVal = pMat[nStart+j].fVal;
//UNUSED2009-05                 }
//UNUSED2009-05             }
//UNUSED2009-05         }
//UNUSED2009-05     }
//UNUSED2009-05 }

void ScMatrix::FillDouble( double fVal, SCSIZE nC1, SCSIZE nR1, SCSIZE nC2, SCSIZE nR2 )
{
	if (ValidColRow( nC1, nR1) && ValidColRow( nC2, nR2))
	{
        if ( nC1 == 0 && nR1 == 0 && nC2 == nColCount-1 && nR2 == nRowCount-1 )
		{
			SCSIZE nEnd = nColCount * nRowCount;
			for ( SCSIZE j=0; j<nEnd; j++ )
				pMat[j].fVal = fVal;
		}
		else
		{
			for ( SCSIZE i=nC1; i<=nC2; i++ )
			{
                SCSIZE nOff1 = i * nRowCount + nR1;
                SCSIZE nOff2 = nOff1 + nR2 - nR1;
				for ( SCSIZE j=nOff1; j<=nOff2; j++ )
					pMat[j].fVal = fVal;
			}
		}
	}
	else
	{
		DBG_ERRORFILE("ScMatrix::FillDouble: dimension error");
	}
}

void ScMatrix::CompareEqual()
{
	SCSIZE n = nColCount * nRowCount;
	if ( mnValType )
	{
		for ( SCSIZE j=0; j<n; j++ )
			if ( IsValueType( mnValType[j]) )		        // else: #WERT!
                if ( ::rtl::math::isFinite( pMat[j].fVal))  // else: DoubleError
                    pMat[j].fVal = (pMat[j].fVal == 0.0);
	}
	else
	{
		for ( SCSIZE j=0; j<n; j++ )
            if ( ::rtl::math::isFinite( pMat[j].fVal))  // else: DoubleError
                pMat[j].fVal = (pMat[j].fVal == 0.0);
	}
}

void ScMatrix::CompareNotEqual()
{
	SCSIZE n = nColCount * nRowCount;
	if ( mnValType )
	{
		for ( SCSIZE j=0; j<n; j++ )
			if ( IsValueType( mnValType[j]) )		        // else: #WERT!
                if ( ::rtl::math::isFinite( pMat[j].fVal))  // else: DoubleError
                    pMat[j].fVal = (pMat[j].fVal != 0.0);
	}
	else
	{
		for ( SCSIZE j=0; j<n; j++ )
            if ( ::rtl::math::isFinite( pMat[j].fVal))  // else: DoubleError
                pMat[j].fVal = (pMat[j].fVal != 0.0);
	}
}

void ScMatrix::CompareLess()
{
	SCSIZE n = nColCount * nRowCount;
	if ( mnValType )
	{
		for ( SCSIZE j=0; j<n; j++ )
			if ( IsValueType( mnValType[j]) )		        // else: #WERT!
                if ( ::rtl::math::isFinite( pMat[j].fVal))  // else: DoubleError
                    pMat[j].fVal = (pMat[j].fVal < 0.0);
	}
	else
	{
		for ( SCSIZE j=0; j<n; j++ )
            if ( ::rtl::math::isFinite( pMat[j].fVal))  // else: DoubleError
                pMat[j].fVal = (pMat[j].fVal < 0.0);
	}
}

void ScMatrix::CompareGreater()
{
	SCSIZE n = nColCount * nRowCount;
	if ( mnValType )
	{
		for ( SCSIZE j=0; j<n; j++ )
			if ( IsValueType( mnValType[j]) )		        // else: #WERT!
                if ( ::rtl::math::isFinite( pMat[j].fVal))  // else: DoubleError
                    pMat[j].fVal = (pMat[j].fVal > 0.0);
	}
	else
	{
		for ( SCSIZE j=0; j<n; j++ )
            if ( ::rtl::math::isFinite( pMat[j].fVal))  // else: DoubleError
                pMat[j].fVal = (pMat[j].fVal > 0.0);
	}
}

void ScMatrix::CompareLessEqual()
{
	SCSIZE n = nColCount * nRowCount;
	if ( mnValType )
	{
		for ( SCSIZE j=0; j<n; j++ )
			if ( IsValueType( mnValType[j]) )		        // else: #WERT!
                if ( ::rtl::math::isFinite( pMat[j].fVal))  // else: DoubleError
                    pMat[j].fVal = (pMat[j].fVal <= 0.0);
	}
	else
	{
		for ( SCSIZE j=0; j<n; j++ )
            if ( ::rtl::math::isFinite( pMat[j].fVal))  // else: DoubleError
                pMat[j].fVal = (pMat[j].fVal <= 0.0);
	}
}

void ScMatrix::CompareGreaterEqual()
{
	SCSIZE n = nColCount * nRowCount;
	if ( mnValType )
	{
		for ( SCSIZE j=0; j<n; j++ )
			if ( IsValueType( mnValType[j]) )		        // else: #WERT!
                if ( ::rtl::math::isFinite( pMat[j].fVal))  // else: DoubleError
                    pMat[j].fVal = (pMat[j].fVal >= 0.0);
	}
	else
	{
		for ( SCSIZE j=0; j<n; j++ )
            if ( ::rtl::math::isFinite( pMat[j].fVal))  // else: DoubleError
                pMat[j].fVal = (pMat[j].fVal >= 0.0);
	}
}

double ScMatrix::And()
{
	SCSIZE n = nColCount * nRowCount;
	bool bAnd = true;
	if ( mnValType )
	{
		for ( SCSIZE j=0; bAnd && j<n; j++ )
        {
			if ( !IsValueType( mnValType[j]) )
            {   // assuming a CompareMat this is an error
                return CreateDoubleError( errIllegalArgument );
            }
            else if ( ::rtl::math::isFinite( pMat[j].fVal))
				bAnd = (pMat[j].fVal != 0.0);
			else
                return pMat[j].fVal;    // DoubleError
        }
	}
	else
	{
		for ( SCSIZE j=0; bAnd && j<n; j++ )
        {
            if ( ::rtl::math::isFinite( pMat[j].fVal))
                bAnd = (pMat[j].fVal != 0.0);
			else
                return pMat[j].fVal;    // DoubleError
        }
	}
	return bAnd;
}

double ScMatrix::Or()
{
	SCSIZE n = nColCount * nRowCount;
	bool bOr = false;
	if ( mnValType )
	{
		for ( SCSIZE j=0; !bOr && j<n; j++ )
			if ( !IsValueType( mnValType[j]) )
            {   // assuming a CompareMat this is an error
                return CreateDoubleError( errIllegalArgument );
            }
            else if ( ::rtl::math::isFinite( pMat[j].fVal))
                bOr = (pMat[j].fVal != 0.0);
			else
                return pMat[j].fVal;    // DoubleError
	}
	else
	{
		for ( SCSIZE j=0; !bOr && j<n; j++ )
            if ( ::rtl::math::isFinite( pMat[j].fVal))
                bOr = (pMat[j].fVal != 0.0);
			else
                return pMat[j].fVal;    // DoubleError
	}
	return bOr;
}

