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

#include <tools/debug.hxx>
#include <vcl/msgbox.hxx>
#include <svl/zforlist.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/types.hxx>

#include <com/sun/star/sheet/DataImportMode.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/sdb/CommandType.hpp>
#include <com/sun/star/sdb/XCompletedExecution.hpp>
#include <com/sun/star/sdbc/DataType.hpp>
#include <com/sun/star/sdbc/XRow.hpp>
#include <com/sun/star/sdbc/XRowSet.hpp>
#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>

#include "dpsdbtab.hxx"
#include "collect.hxx"
#include "global.hxx"
#include "globstr.hrc"
#include "dpcachetable.hxx"
#include "dptabres.hxx"
#include "document.hxx"
#include "dpobject.hxx"

using namespace com::sun::star;

using ::std::vector;
using ::std::hash_map;
using ::std::hash_set;
using ::com::sun::star::uno::Sequence;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Any;
using ::com::sun::star::uno::UNO_QUERY;

#define SC_SERVICE_ROWSET			"com.sun.star.sdb.RowSet"
#define SC_SERVICE_INTHANDLER		"com.sun.star.task.InteractionHandler"

//!	move to a header file?
#define SC_DBPROP_DATASOURCENAME	"DataSourceName"
#define SC_DBPROP_COMMAND			"Command"
#define SC_DBPROP_COMMANDTYPE		"CommandType"
// -----------------------------------------------------------------------
// Wang Xu Ming -- 2009-9-15
// DataPilot Migration - Cache&&Performance
 ScDPTableDataCache* ScImportSourceDesc::GetExistDPObjectCache( ScDocument* pDoc ) const
{
    ScDPTableDataCache* pCache = NULL;
    ScDPCollection* pDPCollection= pDoc->GetDPCollection();
    sal_uInt16 nCount = pDPCollection->GetCount();
    
    for ( short i=nCount-1; i>=0 ; i--)
    {
        if ( const ScImportSourceDesc* pUsedDesc = (*pDPCollection)[i]->GetImportSourceDesc() )
            if ( *this == *pUsedDesc )
            {
                long nID = (*pDPCollection)[i]->GetCacheId();
                if ( nID >= 0  )
                    pCache= pDoc->GetDPObjectCache( nID );
                if ( pCache )
                    return pCache;
            }
    }
    return NULL;
}

ScDPTableDataCache* ScImportSourceDesc::CreateCache( ScDocument* pDoc , long nID  ) const
{
    if ( !pDoc )
		return NULL;

    sal_Int32 nSdbType = -1;
  
    switch ( nType )
    {
    case sheet::DataImportMode_SQL:        nSdbType = sdb::CommandType::COMMAND;  break;
    case sheet::DataImportMode_TABLE:   nSdbType = sdb::CommandType::TABLE;      break;
    case sheet::DataImportMode_QUERY:  nSdbType = sdb::CommandType::QUERY;     break;
    default:
        return NULL;
    }


   ScDPTableDataCache* pCache = GetExistDPObjectCache( pDoc );

    if ( pCache && ( nID < 0 || nID == pCache->GetId() ) )
        return pCache;

    if ( pCache == NULL )
		pCache = new ScDPTableDataCache( pDoc );
	
    uno::Reference<sdbc::XRowSet> xRowSet ;
    try
    {
        xRowSet = uno::Reference<sdbc::XRowSet>(
            comphelper::getProcessServiceFactory()->createInstance(
            rtl::OUString::createFromAscii( SC_SERVICE_ROWSET ) ),
            uno::UNO_QUERY);
        uno::Reference<beans::XPropertySet> xRowProp( xRowSet, uno::UNO_QUERY );
        DBG_ASSERT( xRowProp.is(), "can't get RowSet" );
        if ( xRowProp.is() )
        {
            //
            //  set source parameters
            //
            uno::Any aAny;
            aAny <<= rtl::OUString( aDBName );
            xRowProp->setPropertyValue(
                rtl::OUString::createFromAscii(SC_DBPROP_DATASOURCENAME), aAny );

            aAny <<= rtl::OUString( aObject );
            xRowProp->setPropertyValue(
                rtl::OUString::createFromAscii(SC_DBPROP_COMMAND), aAny );

            aAny <<= nSdbType;
            xRowProp->setPropertyValue(
                rtl::OUString::createFromAscii(SC_DBPROP_COMMANDTYPE), aAny );

            uno::Reference<sdb::XCompletedExecution> xExecute( xRowSet, uno::UNO_QUERY );
            if ( xExecute.is() )
            {
                uno::Reference<task::XInteractionHandler> xHandler(
                    comphelper::getProcessServiceFactory()->createInstance(
                    rtl::OUString::createFromAscii( SC_SERVICE_INTHANDLER ) ),
                    uno::UNO_QUERY);
                xExecute->executeWithCompletion( xHandler );
            }
            else
                xRowSet->execute();
            SvNumberFormatter aFormat( pDoc->GetServiceManager(), ScGlobal::eLnge);
            pCache->InitFromDataBase( xRowSet, *aFormat.GetNullDate() );
            pCache->SetId( nID );
            pDoc->AddDPObjectCache( pCache );
            DBG_TRACE1("Create a cache id = %d \n", pCache->GetId() );
        }
    }
    catch ( sdbc::SQLException& rError )
    {
        //! store error message
        delete pCache;
        pCache = NULL;
        InfoBox aInfoBox( 0, String(rError.Message) );
        aInfoBox.Execute();
    }
    catch ( uno::Exception& )
    {
        delete pCache;
        pCache = NULL;
        DBG_ERROR("Unexpected exception in database");
    }


    ::comphelper::disposeComponent( xRowSet );
     return pCache;
}

ScDPTableDataCache* ScImportSourceDesc::GetCache( ScDocument* pDoc, long nID ) const
{
    ScDPTableDataCache* pCache = pDoc->GetDPObjectCache( nID );
    if ( NULL == pCache && pDoc )
        pCache = GetExistDPObjectCache( pDoc);
    if ( NULL == pCache )
        pCache = CreateCache( pDoc , nID );    
    return pCache;
}

long ScImportSourceDesc:: GetCacheId( ScDocument* pDoc, long nID ) const
{
	ScDPTableDataCache* pCache = GetCache( pDoc,  nID);
	if ( NULL == pCache )
		return -1;
	else 
		return pCache->GetId();
}

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

ScDatabaseDPData::ScDatabaseDPData(
    ScDocument* pDoc,
    const ScImportSourceDesc& rImport, long nCacheId /*=-1 */ ) :
    ScDPTableData(pDoc, rImport.GetCacheId( pDoc, nCacheId) ),
    aCacheTable( pDoc, GetCacheId() )     // base class ID is initialized with the GetCacheId call above
{

}

ScDatabaseDPData::~ScDatabaseDPData()
{
}

void ScDatabaseDPData::DisposeData()
{
	//!	use OpenDatabase here?
     aCacheTable.clear();
}

long ScDatabaseDPData::GetColumnCount()
{
    CreateCacheTable();
    return GetCacheTable().getColSize();
}

// End Comments

String ScDatabaseDPData::getDimensionName(long nColumn)
{
	if (getIsDataLayoutDimension(nColumn))
	{
		//!	different internal and display names?
		//return "Data";
		return ScGlobal::GetRscString(STR_PIVOT_DATA);
	}

    CreateCacheTable();
	return aCacheTable.getFieldName((SCCOL)nColumn);
}

sal_Bool ScDatabaseDPData::getIsDataLayoutDimension(long nColumn)
{
	return ( nColumn == GetCacheTable().getColSize());
}

sal_Bool ScDatabaseDPData::IsDateDimension(long /* nDim */)
{
	//!	later...
	return sal_False;
}

void ScDatabaseDPData::SetEmptyFlags( sal_Bool /* bIgnoreEmptyRows */, sal_Bool /* bRepeatIfEmpty */ )
{
	//	not used for database data
	//!	disable flags
}

void ScDatabaseDPData::CreateCacheTable()
{
    if (!aCacheTable.empty())
        return;

    aCacheTable.fillTable();
}

void ScDatabaseDPData::FilterCacheTable(const vector<ScDPCacheTable::Criterion>& rCriteria, const hash_set<sal_Int32>& rCatDims)
{
    CreateCacheTable();
    aCacheTable.filterByPageDimension(
        rCriteria, (IsRepeatIfEmpty() ? rCatDims : hash_set<sal_Int32>()));
}

void ScDatabaseDPData::GetDrillDownData(const vector<ScDPCacheTable::Criterion>& rCriteria, const hash_set<sal_Int32>& rCatDims, Sequence< Sequence<Any> >& rData)
{
    CreateCacheTable();
    sal_Int32 nRowSize = aCacheTable.getRowSize();
    if (!nRowSize)
        return;

    aCacheTable.filterTable(
        rCriteria, rData, IsRepeatIfEmpty() ? rCatDims : hash_set<sal_Int32>());
}

void ScDatabaseDPData::CalcResults(CalcInfo& rInfo, bool bAutoShow)
{
    CreateCacheTable();
    CalcResultsFromCacheTable( aCacheTable, rInfo, bAutoShow);
}

const ScDPCacheTable& ScDatabaseDPData::GetCacheTable() const
{
    return aCacheTable;
}

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





