/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifdef _MSC_VER
#pragma hdrstop
#endif

// INCLUDE ---------------------------------------------------------------

#include <tools/debug.hxx>
#include <math.h>
#include <string.h>
#include "consoli.hxx"
#include "document.hxx"
#include "globstr.hrc"
#include "subtotal.hxx"
#include "cell.hxx"
namespace binfilter {

#define SC_CONS_NOTFOUND    0xFFFF


/*N*/ void lcl_AddString( String**& pData, USHORT& nCount, const String& rInsert )
/*N*/ {
/*N*/   String** pOldData = pData;
/*N*/   pData = new String*[ nCount+1 ];
/*N*/   if (pOldData)
/*N*/   {
/*N*/       memmove( pData, pOldData, nCount * sizeof(String*) );
/*N*/       delete[] pOldData;
/*N*/   }
/*N*/   pData[nCount] = new String(rInsert);
/*N*/   ++nCount;
/*N*/ }

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

/*N*/ ScConsData::ScConsData() :
/*N*/   eFunction(SUBTOTAL_FUNC_SUM),
/*N*/   bReference(FALSE),
/*N*/   bColByName(FALSE),
/*N*/   bRowByName(FALSE),
/*N*/   bSubTitles(FALSE),
/*N*/   nColCount(0),
/*N*/   nRowCount(0),
/*N*/   ppUsed(NULL),
/*N*/   ppSum(NULL),
/*N*/   ppCount(NULL),
/*N*/   ppSumSqr(NULL),
/*N*/   ppRefs(NULL),
/*N*/   ppColHeaders(NULL),
/*N*/   ppRowHeaders(NULL),
/*N*/   nDataCount(0),
/*N*/   nTitleCount(0),
/*N*/   ppTitles(NULL),
/*N*/   ppTitlePos(NULL),
/*N*/   bCornerUsed(FALSE)
/*N*/ {
/*N*/ }

/*N*/ ScConsData::~ScConsData()
/*N*/ {
/*N*/   DeleteData();
/*N*/ }


/*N*/ #define DELETEARR(ppArray,nCount) \
/*N*/ {                                 \
/*N*/   if (ppArray)                    \
/*N*/       for(USHORT i=0; i<nCount; i++)      \
/*N*/           delete[] ppArray[i];    \
/*N*/   delete[] ppArray;               \
/*N*/   ppArray = NULL;                 \
/*N*/ }
/*N*/
/*N*/ #define DELETESTR(ppArray,nCount) \
/*N*/ {                                 \
/*N*/   if (ppArray)                    \
/*N*/       for(USHORT i=0; i<nCount; i++)      \
/*N*/           delete ppArray[i];      \
/*N*/   delete[] ppArray;               \
/*N*/   ppArray = NULL;                 \
/*N*/ }

/*N*/ void ScConsData::DeleteData()
/*N*/ {
/*N*/   if (ppRefs)
/*N*/       for (USHORT i=0; i<nColCount; i++)
/*N*/       {
/*N*/           for (USHORT j=0; j<nRowCount; j++)
/*N*/               if (ppUsed[i][j])
/*N*/                   ppRefs[i][j].Clear();
/*N*/           delete[] ppRefs[i];
/*N*/       }
/*N*/   delete[] ppRefs;
/*N*/   ppRefs = NULL;
/*N*/
/*N*/   DELETEARR( ppCount, nColCount );
/*N*/   DELETEARR( ppSum,   nColCount );
/*N*/   DELETEARR( ppSumSqr,nColCount );
/*N*/   DELETEARR( ppUsed,  nColCount );                // erst nach ppRefs !!!
/*N*/   DELETEARR( ppTitlePos, nRowCount );
/*N*/   DELETESTR( ppColHeaders, nColCount );
/*N*/   DELETESTR( ppRowHeaders, nRowCount );
/*N*/   DELETESTR( ppTitles, nTitleCount );
/*N*/   nTitleCount = 0;
/*N*/   nDataCount = 0;
/*N*/
/*N*/   if (bColByName) nColCount = 0;                  // sonst stimmt ppColHeaders nicht
/*N*/   if (bRowByName) nRowCount = 0;
/*N*/
/*N*/   bCornerUsed = FALSE;
/*N*/   aCornerText.Erase();
/*N*/ }

/*N*/ #undef DELETEARR
/*N*/ #undef DELETESTR

/*N*/ void ScConsData::InitData( BOOL bDelete )
/*N*/ {
/*N*/   USHORT i;
/*N*/   if (bDelete)
/*N*/       DeleteData();
/*N*/
/*N*/   if (bReference && nColCount && !ppRefs)
/*N*/   {
/*N*/       ppRefs = new ScReferenceList*[nColCount];
/*N*/       for (i=0; i<nColCount; i++)
/*N*/           ppRefs[i] = new ScReferenceList[nRowCount];
/*N*/   }
/*N*/   else if (nColCount && !ppCount)
/*N*/   {
/*N*/       ppCount  = new double*[nColCount];
/*N*/       ppSum    = new double*[nColCount];
/*N*/       ppSumSqr = new double*[nColCount];
/*N*/       for (i=0; i<nColCount; i++)
/*N*/       {
/*N*/           ppCount[i]  = new double[nRowCount];
/*N*/           ppSum[i]    = new double[nRowCount];
/*N*/           ppSumSqr[i] = new double[nRowCount];
/*N*/       }
/*N*/   }
/*N*/
/*N*/   if (nColCount && !ppUsed)
/*N*/   {
/*N*/       ppUsed = new BOOL*[nColCount];
/*N*/       for (i=0; i<nColCount; i++)
/*N*/       {
/*N*/           ppUsed[i] = new BOOL[nRowCount];
/*N*/           memset( ppUsed[i], 0, nRowCount * sizeof(BOOL) );
/*N*/       }
/*N*/   }
/*N*/
/*N*/   if (nRowCount && nDataCount && !ppTitlePos)
/*N*/   {
/*N*/       ppTitlePos = new USHORT*[nRowCount];
/*N*/       for (i=0; i<nRowCount; i++)
/*N*/       {
/*N*/           ppTitlePos[i] = new USHORT[nDataCount];
/*N*/           memset( ppTitlePos[i], 0, nDataCount * sizeof(USHORT) );    //! unnoetig ?
/*N*/       }
/*N*/   }
/*N*/
/*N*/   //  CornerText: einzelner String
/*N*/ }

/*N*/ void ScConsData::DoneFields()
/*N*/ {
/*N*/   InitData(FALSE);
/*N*/ }

/*N*/ void ScConsData::SetSize( USHORT nCols, USHORT nRows )
/*N*/ {
/*N*/   DeleteData();
/*N*/   nColCount = nCols;
/*N*/   nRowCount = nRows;
/*N*/ }

/*N*/ void ScConsData::GetSize( USHORT& rCols, USHORT& rRows ) const
/*N*/ {
/*N*/   rCols = nColCount;
/*N*/   rRows = nRowCount;
/*N*/ }

/*N*/ void ScConsData::SetFlags( ScSubTotalFunc eFunc, BOOL bColName, BOOL bRowName, BOOL bRef )
/*N*/ {
/*N*/   DeleteData();
/*N*/   bReference = bRef;
/*N*/   bColByName = bColName;
/*N*/   if (bColName) nColCount = 0;
/*N*/   bRowByName = bRowName;
/*N*/   if (bRowName) nRowCount = 0;
/*N*/   eFunction = eFunc;
/*N*/ }

/*N*/ void ScConsData::AddFields( ScDocument* pSrcDoc, USHORT nTab,
/*N*/                           USHORT nCol1, USHORT nRow1, USHORT nCol2, USHORT nRow2 )
/*N*/ {
/*N*/   ++nDataCount;
/*N*/
/*N*/   String aTitle;
/*N*/
/*N*/   USHORT nStartCol = nCol1;
/*N*/   USHORT nStartRow = nRow1;
/*N*/   if (bColByName) ++nStartRow;
/*N*/   if (bRowByName) ++nStartCol;
/*N*/
/*N*/   if (bColByName)
/*N*/   {
/*N*/       for (USHORT nCol=nStartCol; nCol<=nCol2; nCol++)
/*N*/       {
/*N*/           pSrcDoc->GetString( nCol, nRow1, nTab, aTitle );
/*N*/           if (aTitle.Len())
/*N*/           {
/*N*/               BOOL bFound = FALSE;
/*N*/               for (USHORT i=0; i<nColCount && !bFound; i++)
/*N*/                   if ( *ppColHeaders[i] == aTitle )
/*N*/                       bFound = TRUE;
/*N*/               if (!bFound)
/*N*/                   lcl_AddString( ppColHeaders, nColCount, aTitle );
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/
/*N*/   if (bRowByName)
/*N*/   {
/*N*/       for (USHORT nRow=nStartRow; nRow<=nRow2; nRow++)
/*N*/       {
/*N*/           pSrcDoc->GetString( nCol1, nRow, nTab, aTitle );
/*N*/           if (aTitle.Len())
/*N*/           {
/*N*/               BOOL bFound = FALSE;
/*N*/               for (USHORT i=0; i<nRowCount && !bFound; i++)
/*N*/                   if ( *ppRowHeaders[i] == aTitle )
/*N*/                       bFound = TRUE;
/*N*/               if (!bFound)
/*N*/                   lcl_AddString( ppRowHeaders, nRowCount, aTitle );
/*N*/           }
/*N*/       }
/*N*/   }
/*N*/ }

/*N*/ void ScConsData::AddName( const String& rName )
/*N*/ {
/*N*/   USHORT nArrX;
/*N*/   USHORT nArrY;
/*N*/
/*N*/   if (bReference)
/*N*/   {
/*N*/       lcl_AddString( ppTitles, nTitleCount, rName );
/*N*/
/*N*/       for (nArrY=0; nArrY<nRowCount; nArrY++)
/*N*/       {
/*N*/           //  Daten auf gleiche Laenge bringen
/*N*/
/*N*/           USHORT nMax = 0;
/*N*/           for (nArrX=0; nArrX<nColCount; nArrX++)
/*N*/               if (ppUsed[nArrX][nArrY])
/*N*/                   nMax = Max( nMax, ppRefs[nArrX][nArrY].GetCount() );
/*N*/
/*N*/           for (nArrX=0; nArrX<nColCount; nArrX++)
/*N*/           {
/*N*/               if (!ppUsed[nArrX][nArrY])
/*N*/               {
/*N*/                   ppUsed[nArrX][nArrY] = TRUE;
/*N*/                   ppRefs[nArrX][nArrY].Init();
/*N*/               }
/*N*/               ppRefs[nArrX][nArrY].SetFullSize(nMax);
/*N*/           }
/*N*/
/*N*/           //  Positionen eintragen
/*N*/
/*N*/           if (ppTitlePos)
/*N*/               if (nTitleCount < nDataCount)
/*N*/                   ppTitlePos[nArrY][nTitleCount] = nMax;
/*N*/       }
/*N*/   }
/*N*/ }

/*N*/ double lcl_CalcData( ScSubTotalFunc eFunc,
/*N*/                       double fCount, double fSum, double fSumSqr)
/*N*/ {
/*N*/   if (fCount < 0.0)
/*N*/       return 0.0;
/*N*/   double fVal = 0.0;
/*N*/   switch (eFunc)
/*N*/   {
/*N*/       case SUBTOTAL_FUNC_CNT:
/*N*/       case SUBTOTAL_FUNC_CNT2:
/*N*/           fVal = fCount;
/*N*/           break;
/*N*/       case SUBTOTAL_FUNC_SUM:
/*N*/       case SUBTOTAL_FUNC_MAX:
/*N*/       case SUBTOTAL_FUNC_MIN:
/*N*/       case SUBTOTAL_FUNC_PROD:
/*N*/           fVal = fSum;
/*N*/           break;
/*N*/       case SUBTOTAL_FUNC_AVE:
/*N*/           if (fCount > 0.0)
/*N*/               fVal = fSum / fCount;
/*N*/           else
/*N*/               fCount = -MAXDOUBLE;
/*N*/           break;
/*N*/       case SUBTOTAL_FUNC_STD:
/*N*/       {
/*N*/           if (fCount > 1 && SubTotal::SafeMult(fSum, fSum))
/*N*/               fVal = sqrt((fSumSqr - fSum/fCount)/(fCount-1.0));
/*N*/           else
/*N*/               fCount = -MAXDOUBLE;
/*N*/       }
/*N*/           break;
/*N*/       case SUBTOTAL_FUNC_STDP:
/*N*/       {
/*N*/           if (fCount > 0 && SubTotal::SafeMult(fSum, fSum))
/*N*/               fVal = sqrt((fSumSqr - fSum/fCount)/fCount);
/*N*/           else
/*N*/               fCount = -MAXDOUBLE;
/*N*/       }
/*N*/           break;
/*N*/       case SUBTOTAL_FUNC_VAR:
/*N*/       {
/*N*/           if (fCount > 1 && SubTotal::SafeMult(fSum, fSum))
/*N*/               fVal = (fSumSqr - fSum/fCount)/(fCount-1.0);
/*N*/           else
/*N*/               fCount = -MAXDOUBLE;
/*N*/       }
/*N*/           break;
/*N*/       case SUBTOTAL_FUNC_VARP:
/*N*/       {
/*N*/           if (fCount > 0 && SubTotal::SafeMult(fSum, fSum))
/*N*/               fVal = (fSumSqr - fSum/fCount)/fCount;
/*N*/           else
/*N*/               fCount = -MAXDOUBLE;
/*N*/       }
/*N*/           break;
/*N*/       default:
/*N*/       {
/*N*/           OSL_FAIL("unbekannte Funktion bei Consoli::CalcData");
/*N*/           fCount = -MAXDOUBLE;
/*N*/       }
/*N*/           break;
/*N*/   }
/*N*/   return fVal;
/*N*/ }

/*N*/ void ScConsData::AddData( ScDocument* pSrcDoc, USHORT nTab,
/*N*/                           USHORT nCol1, USHORT nRow1, USHORT nCol2, USHORT nRow2 )
/*N*/ {
/*N*/   PutInOrder(nCol1,nCol2);
/*N*/   PutInOrder(nRow1,nRow2);
/*N*/   if ( nCol2 >= nCol1 + nColCount && !bColByName )
/*N*/   {
/*N*/       DBG_ASSERT(0,"Bereich zu gross");
/*N*/       nCol2 = nCol1 + nColCount - 1;
/*N*/   }
/*N*/   if ( nRow2 >= nRow1 + nRowCount && !bRowByName )
/*N*/   {
/*N*/       DBG_ASSERT(0,"Bereich zu gross");
/*N*/       nRow2 = nRow1 + nRowCount - 1;
/*N*/   }
/*N*/
/*N*/   USHORT nCol;
/*N*/   USHORT nRow;
/*N*/
/*N*/   //      Ecke links oben
/*N*/
/*N*/   if ( bColByName && bRowByName )
/*N*/   {
/*N*/       String aThisCorner;
/*N*/       pSrcDoc->GetString(nCol1,nRow1,nTab,aThisCorner);
/*N*/       if (bCornerUsed)
/*N*/       {
/*N*/           if (aCornerText != aThisCorner)
/*N*/               aCornerText.Erase();
/*N*/       }
/*N*/       else
/*N*/       {
/*N*/           aCornerText = aThisCorner;
/*N*/           bCornerUsed = TRUE;
/*N*/       }
/*N*/   }
/*N*/
/*N*/   //      Titel suchen
/*N*/
/*N*/   USHORT nStartCol = nCol1;
/*N*/   USHORT nStartRow = nRow1;
/*N*/   if (bColByName) ++nStartRow;
/*N*/   if (bRowByName) ++nStartCol;
/*N*/   String aTitle;
/*N*/   USHORT* pDestCols = NULL;
/*N*/   USHORT* pDestRows = NULL;
/*N*/   if (bColByName)
/*N*/   {
/*N*/       pDestCols = new USHORT[nCol2-nStartCol+1];
/*N*/       for (nCol=nStartCol; nCol<=nCol2; nCol++)
/*N*/       {
/*N*/           pSrcDoc->GetString(nCol,nRow1,nTab,aTitle);
/*N*/           USHORT nPos = SC_CONS_NOTFOUND;
/*N*/           if (aTitle.Len())
/*N*/           {
/*N*/               BOOL bFound = FALSE;
/*N*/               for (USHORT i=0; i<nColCount && !bFound; i++)
/*N*/                   if ( *ppColHeaders[i] == aTitle )
/*N*/                   {
/*N*/                       nPos = i;
/*N*/                       bFound = TRUE;
/*N*/                   }
/*N*/               DBG_ASSERT(bFound, "Spalte nicht gefunden");
/*N*/           }
/*N*/           pDestCols[nCol-nStartCol] = nPos;
/*N*/       }
/*N*/   }
/*N*/   if (bRowByName)
/*N*/   {
/*N*/       pDestRows = new USHORT[nRow2-nStartRow+1];
/*N*/       for (nRow=nStartRow; nRow<=nRow2; nRow++)
/*N*/       {
/*N*/           pSrcDoc->GetString(nCol1,nRow,nTab,aTitle);
/*N*/           USHORT nPos = SC_CONS_NOTFOUND;
/*N*/           if (aTitle.Len())
/*N*/           {
/*N*/               BOOL bFound = FALSE;
/*N*/               for (USHORT i=0; i<nRowCount && !bFound; i++)
/*N*/                   if ( *ppRowHeaders[i] == aTitle )
/*N*/                   {
/*N*/                       nPos = i;
/*N*/                       bFound = TRUE;
/*N*/                   }
/*N*/               DBG_ASSERT(bFound, "Zeile nicht gefunden");
/*N*/           }
/*N*/           pDestRows[nRow-nStartRow] = nPos;
/*N*/       }
/*N*/   }
/*N*/   nCol1 = nStartCol;
/*N*/   nRow1 = nStartRow;
/*N*/
/*N*/   delete[] pDestCols;
/*N*/   delete[] pDestRows;
/*N*/ }

//  fertige Daten ins Dokument schreiben
//! optimieren nach Spalten?

/*N*/ void ScConsData::OutputToDocument( ScDocument* pDestDoc, USHORT nCol, USHORT nRow, USHORT nTab )
/*N*/ {
/*N*/   USHORT nArrX;
/*N*/   USHORT nArrY;
/*N*/   USHORT i;
/*N*/
/*N*/   //  Ecke links oben
/*N*/
/*N*/   if ( bColByName && bRowByName && aCornerText.Len() )
/*N*/       pDestDoc->SetString( nCol, nRow, nTab, aCornerText );
/*N*/
/*N*/   //  Titel
/*N*/
/*N*/   USHORT nStartCol = nCol;
/*N*/   USHORT nStartRow = nRow;
/*N*/   if (bColByName) ++nStartRow;
/*N*/   if (bRowByName) ++nStartCol;
/*N*/
/*N*/   if (bColByName)
/*N*/       for (i=0; i<nColCount; i++)
/*N*/           pDestDoc->SetString( nStartCol+i, nRow, nTab, *ppColHeaders[i] );
/*N*/   if (bRowByName)
/*N*/       for (i=0; i<nRowCount; i++)
/*N*/           pDestDoc->SetString( nCol, nStartRow+i, nTab, *ppRowHeaders[i] );
/*N*/
/*N*/   nCol = nStartCol;
/*N*/   nRow = nStartRow;
/*N*/
/*N*/   //  Daten
/*N*/
/*N*/   if ( ppCount && ppUsed )                            // Werte direkt einfuegen
/*N*/   {
/*N*/       for (nArrX=0; nArrX<nColCount; nArrX++)
/*N*/           for (nArrY=0; nArrY<nRowCount; nArrY++)
/*N*/               if (ppUsed[nArrX][nArrY])
/*N*/               {
/*N*/                   double fVal = lcl_CalcData( eFunction, ppCount[nArrX][nArrY],
/*N*/                                               ppSum[nArrX][nArrY],
/*N*/                                               ppSumSqr[nArrX][nArrY]);
/*N*/                   if (ppCount[nArrX][nArrY] < 0.0)
/*N*/                       pDestDoc->SetError( nCol+nArrX, nRow+nArrY, nTab, errNoValue );
/*N*/                   else
/*N*/                       pDestDoc->SetValue( nCol+nArrX, nRow+nArrY, nTab, fVal );
/*N*/               }
/*N*/   }
/*N*/
/*N*/   if ( ppRefs && ppUsed )                             // Referenzen einfuegen
/*N*/   {
/*N*/                               //! unterscheiden, ob nach Kategorien aufgeteilt
/*N*/       String aString;
/*N*/
/*N*/       SingleRefData aSRef;        // Daten fuer Referenz-Formelzellen
/*N*/       aSRef.InitFlags();
/*N*/       aSRef.SetFlag3D(TRUE);
/*N*/
/*N*/       ComplRefData aCRef;         // Daten fuer Summen-Zellen
/*N*/       aCRef.InitFlags();
/*N*/       aCRef.Ref1.SetColRel(TRUE); aCRef.Ref1.SetRowRel(TRUE); aCRef.Ref1.SetTabRel(TRUE);
/*N*/       aCRef.Ref2.SetColRel(TRUE); aCRef.Ref2.SetRowRel(TRUE); aCRef.Ref2.SetTabRel(TRUE);
/*N*/   }
/*N*/ }


}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
