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

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_connectivity.hxx"
#include "ado/ADatabaseMetaData.hxx"
#include "ado/ADatabaseMetaDataResultSetMetaData.hxx"
#include "ado/Awrapado.hxx"
#include "ado/AGroup.hxx"
#include "ado/adoimp.hxx"
#include "ado/AIndex.hxx"
#include "ado/AKey.hxx"
#include "ado/ATable.hxx"
#include <com/sun/star/sdbc/DataType.hpp>
#include <com/sun/star/sdbc/ProcedureResult.hpp>
#include <com/sun/star/sdbc/ColumnValue.hpp>
#ifdef DELETE
#undef DELETE
#endif
#include <com/sun/star/sdbcx/Privilege.hpp>
#include <com/sun/star/sdbcx/PrivilegeObject.hpp>
#include <com/sun/star/sdbc/KeyRule.hpp>
#include <com/sun/star/sdbcx/KeyType.hpp>

using namespace connectivity::ado;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::sdbcx;
using namespace ::com::sun::star::uno;

// -------------------------------------------------------------------------
void ODatabaseMetaData::fillLiterals()
{
	ADORecordset *pRecordset = NULL;
	OLEVariant  vtEmpty;
	vtEmpty.setNoArg();
	m_pADOConnection->OpenSchema(adSchemaDBInfoLiterals,vtEmpty,vtEmpty,&pRecordset);

	ADOS::ThrowException(*m_pADOConnection,*this);

	OSL_ENSURE(pRecordset,"fillLiterals: no resultset!");
	if ( pRecordset )
	{
		WpADORecordset aRecordset(pRecordset);

		aRecordset.MoveFirst();
		OLEVariant  aValue;
		LiteralInfo aInfo;
		while(!aRecordset.IsAtEOF())
		{
			WpOLEAppendCollection<ADOFields, ADOField, WpADOField>	aFields(aRecordset.GetFields());
			WpADOField aField(aFields.GetItem(1));
			aInfo.pwszLiteralValue = aField.get_Value();
			aField = aFields.GetItem(5);
			aInfo.fSupported = aField.get_Value();
			aField = aFields.GetItem(6);
			aInfo.cchMaxLen = aField.get_Value().getUInt32();

			aField = aFields.GetItem(4);
			sal_uInt32 nId = aField.get_Value().getUInt32();
			m_aLiteralInfo[nId] = aInfo;

			aRecordset.MoveNext();
		}
		aRecordset.Close();
	}
}
// -------------------------------------------------------------------------
sal_Int32 ODatabaseMetaData::getMaxSize(sal_uInt32 _nId)
{
	if(!m_aLiteralInfo.size())
		fillLiterals();

	sal_Int32 nSize = 0;
	::std::map<sal_uInt32,LiteralInfo>::const_iterator aIter = m_aLiteralInfo.find(_nId);
	if(aIter != m_aLiteralInfo.end() && (*aIter).second.fSupported)
		nSize = ((*aIter).second.cchMaxLen == (-1)) ? 0 : (*aIter).second.cchMaxLen;
	return nSize;
}
// -------------------------------------------------------------------------
sal_Bool ODatabaseMetaData::isCapable(sal_uInt32 _nId)
{
	if(!m_aLiteralInfo.size())
		fillLiterals();
	sal_Bool bSupported = sal_False;
	::std::map<sal_uInt32,LiteralInfo>::const_iterator aIter = m_aLiteralInfo.find(_nId);
	if(aIter != m_aLiteralInfo.end())
		bSupported = (*aIter).second.fSupported;
	return bSupported;
}

// -------------------------------------------------------------------------
::rtl::OUString ODatabaseMetaData::getLiteral(sal_uInt32 _nId)
{
	if(!m_aLiteralInfo.size())
		fillLiterals();
	::rtl::OUString sStr;
	::std::map<sal_uInt32,LiteralInfo>::const_iterator aIter = m_aLiteralInfo.find(_nId);
	if(aIter != m_aLiteralInfo.end() && (*aIter).second.fSupported)
		sStr = (*aIter).second.pwszLiteralValue;
	return sStr;
}
// -----------------------------------------------------------------------------
// -------------------------------------------------------------------------
void ODatabaseMetaDataResultSetMetaData::setColumnPrivilegesMap()
{
	m_mColumns[8] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("IS_GRANTABLE"),
		ColumnValue::NULLABLE,
		3,3,0,
		DataType::VARCHAR);
}
// -------------------------------------------------------------------------
void ODatabaseMetaDataResultSetMetaData::setColumnsMap()
{
	m_mColumns[6] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("TYPE_NAME"),
		ColumnValue::NO_NULLS,
		0,0,0,
		DataType::VARCHAR);
	m_mColumns[11] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("NULLABLE"),
		ColumnValue::NO_NULLS,
		1,1,0,
		DataType::INTEGER);
	m_mColumns[12] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("REMARKS"),
		ColumnValue::NULLABLE,
		0,0,0,
		DataType::VARCHAR);
	m_mColumns[13] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("COLUMN_DEF"),
		ColumnValue::NULLABLE,
		0,0,0,
		DataType::VARCHAR);
	m_mColumns[14] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("SQL_DATA_TYPE"),
		ColumnValue::NO_NULLS,
		1,1,0,
		DataType::INTEGER);
	m_mColumns[15] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("SQL_DATETIME_SUB"),
		ColumnValue::NO_NULLS,
		1,1,0,
		DataType::INTEGER);
	m_mColumns[16] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("CHAR_OCTET_LENGTH"),
		ColumnValue::NO_NULLS,
		1,1,0,
		DataType::INTEGER);
}
// -------------------------------------------------------------------------
void ODatabaseMetaDataResultSetMetaData::setTablesMap()
{
	m_mColumns[5] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("REMARKS"),
		ColumnValue::NULLABLE,
		0,0,0,
		DataType::VARCHAR);
}
// -------------------------------------------------------------------------
void ODatabaseMetaDataResultSetMetaData::setProcedureColumnsMap()
{
	m_mColumns[12] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("NULLABLE"),
		ColumnValue::NO_NULLS,
		1,1,0,
		DataType::INTEGER);
}
// -------------------------------------------------------------------------
void ODatabaseMetaDataResultSetMetaData::setPrimaryKeysMap()
{
	m_mColumns[5] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("KEY_SEQ"),
		ColumnValue::NO_NULLS,
		1,1,0,
		DataType::INTEGER);
	m_mColumns[6] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("PK_NAME"),
		ColumnValue::NULLABLE,
		0,0,0,
		DataType::VARCHAR);
}
// -------------------------------------------------------------------------
void ODatabaseMetaDataResultSetMetaData::setIndexInfoMap()
{
	m_mColumns[4] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("NON_UNIQUE"),
		ColumnValue::NO_NULLS,
		1,1,0,
		DataType::BIT);
	m_mColumns[5] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("INDEX_QUALIFIER"),
		ColumnValue::NULLABLE,
		0,0,0,
		DataType::VARCHAR);
	m_mColumns[10] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("ASC_OR_DESC"),
		ColumnValue::NULLABLE,
		0,0,0,
		DataType::VARCHAR);
}
// -------------------------------------------------------------------------
void ODatabaseMetaDataResultSetMetaData::setTablePrivilegesMap()
{
	m_mColumns[6] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("PRIVILEGE"),
		ColumnValue::NULLABLE,
		0,0,0,
		DataType::VARCHAR);
	m_mColumns[7] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("IS_GRANTABLE"),
		ColumnValue::NULLABLE,
		0,0,0,
		DataType::VARCHAR);
}
// -------------------------------------------------------------------------
void ODatabaseMetaDataResultSetMetaData::setCrossReferenceMap()
{
	m_mColumns[9] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("KEY_SEQ"),
		ColumnValue::NO_NULLS,
		1,1,0,
		DataType::INTEGER);
}
// -------------------------------------------------------------------------
void ODatabaseMetaDataResultSetMetaData::setTypeInfoMap()
{
	m_mColumns[3] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("PRECISION"),
		ColumnValue::NO_NULLS,
		1,1,0,
		DataType::INTEGER);
	m_mColumns[7] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("NULLABLE"),
		ColumnValue::NO_NULLS,
		1,1,0,
		DataType::INTEGER);
	m_mColumns[12] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("AUTO_INCREMENT"),
		ColumnValue::NO_NULLS,
		1,1,0,
		DataType::BIT);
	m_mColumns[16] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("SQL_DATA_TYPE"),
		ColumnValue::NO_NULLS,
		1,1,0,
		DataType::INTEGER);
	m_mColumns[17] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("SQL_DATETIME_SUB"),
		ColumnValue::NO_NULLS,
		1,1,0,
		DataType::INTEGER);
	m_mColumns[18] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("NUM_PREC_RADIX"),
		ColumnValue::NO_NULLS,
		1,1,0,
		DataType::INTEGER);
}
// -------------------------------------------------------------------------
void ODatabaseMetaDataResultSetMetaData::setProceduresMap()
{
	m_mColumns[7] = OColumn(::rtl::OUString(),::rtl::OUString::createFromAscii("REMARKS"),
		ColumnValue::NULLABLE,
		0,0,0,
		DataType::VARCHAR);
}
// -------------------------------------------------------------------------
sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isSearchable( sal_Int32 column ) throw(SQLException, RuntimeException)
{
	if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
		return (*m_mColumnsIter).second.isSearchable();
	return sal_True;
}
// -------------------------------------------------------------------------
sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isAutoIncrement( sal_Int32 column ) throw(SQLException, RuntimeException)
{
	if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
		return (*m_mColumnsIter).second.isAutoIncrement();
	return sal_False;
}
// -------------------------------------------------------------------------
::rtl::OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnServiceName( sal_Int32 column ) throw(SQLException, RuntimeException)
{
	if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
		return (*m_mColumnsIter).second.getColumnServiceName();
	return ::rtl::OUString();
}
// -------------------------------------------------------------------------
::rtl::OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getTableName( sal_Int32 column ) throw(SQLException, RuntimeException)
{
	if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
		return (*m_mColumnsIter).second.getTableName();
	return ::rtl::OUString();
}
// -------------------------------------------------------------------------
::rtl::OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getCatalogName( sal_Int32 column ) throw(SQLException, RuntimeException)
{
	if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
		return (*m_mColumnsIter).second.getCatalogName();
	return ::rtl::OUString();
}
// -------------------------------------------------------------------------
::rtl::OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getColumnTypeName( sal_Int32 column ) throw(SQLException, RuntimeException)
{
	if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
		return (*m_mColumnsIter).second.getColumnTypeName();
	return ::rtl::OUString();
}
// -------------------------------------------------------------------------

sal_Bool SAL_CALL ODatabaseMetaDataResultSetMetaData::isCaseSensitive( sal_Int32 column ) throw(SQLException, RuntimeException)
{
	if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
		return (*m_mColumnsIter).second.isCaseSensitive();
	return sal_True;
}
// -------------------------------------------------------------------------

::rtl::OUString SAL_CALL ODatabaseMetaDataResultSetMetaData::getSchemaName( sal_Int32 column ) throw(SQLException, RuntimeException)
{
	if(m_mColumns.size() && (m_mColumnsIter = m_mColumns.find(column)) != m_mColumns.end())
		return (*m_mColumnsIter).second.getSchemaName();
	return ::rtl::OUString();
}
// -----------------------------------------------------------------------------
// -------------------------------------------------------------------------
ObjectTypeEnum OAdoGroup::MapObjectType(sal_Int32 _ObjType)
{
	ObjectTypeEnum eNumType= adPermObjTable;
	switch(_ObjType)
	{
        case PrivilegeObject::TABLE:
			break;
        case PrivilegeObject::VIEW:
			eNumType = adPermObjView;
			break;
        case PrivilegeObject::COLUMN:
			eNumType = adPermObjColumn;
			break;
	}
	return eNumType;
}
// -------------------------------------------------------------------------
sal_Int32 OAdoGroup::MapRight(RightsEnum _eNum)
{
	sal_Int32 nRight = 0;
	if(_eNum & adRightRead)
                nRight |= Privilege::SELECT;
	if(_eNum & adRightInsert)
                nRight |= Privilege::INSERT;
	if(_eNum & adRightUpdate)
                nRight |= Privilege::UPDATE;
	if(_eNum & adRightDelete)
                nRight |= Privilege::DELETE;
	if(_eNum & adRightReadDesign)
                nRight |= Privilege::READ;
	if(_eNum & adRightCreate)
                nRight |= Privilege::CREATE;
	if(_eNum & adRightWriteDesign)
                nRight |= Privilege::ALTER;
	if(_eNum & adRightReference)
                nRight |= Privilege::REFERENCE;
	if(_eNum & adRightDrop)
                nRight |= Privilege::DROP;

	return nRight;
}
// -------------------------------------------------------------------------
RightsEnum OAdoGroup::Map2Right(sal_Int32 _eNum)
{
	sal_Int32 nRight = adRightNone;
        if(_eNum & Privilege::SELECT)
		nRight |= adRightRead;

        if(_eNum & Privilege::INSERT)
		nRight |= adRightInsert;

        if(_eNum & Privilege::UPDATE)
		nRight |= adRightUpdate;

        if(_eNum & Privilege::DELETE)
		nRight |= adRightDelete;

        if(_eNum & Privilege::READ)
		nRight |= adRightReadDesign;

        if(_eNum & Privilege::CREATE)
		nRight |= adRightCreate;

        if(_eNum & Privilege::ALTER)
		nRight |= adRightWriteDesign;

        if(_eNum & Privilege::REFERENCE)
		nRight |= adRightReference;

        if(_eNum & Privilege::DROP)
		nRight |= adRightDrop;

	return (RightsEnum)nRight;
}
// -------------------------------------------------------------------------
void WpADOIndex::Create()
{
	HRESULT         hr = -1;

	_ADOIndex* pIndex = NULL;
	hr = CoCreateInstance(ADOS::CLSID_ADOINDEX_25,
						  NULL,
						  CLSCTX_INPROC_SERVER,
						  ADOS::IID_ADOINDEX_25,
						  (void**)&pIndex );


	if( !FAILED( hr ) )
	{
		operator=( pIndex );
		pIndex->Release();
	}
}
// -------------------------------------------------------------------------
void OAdoIndex::fillPropertyValues()
{
	if(m_aIndex.IsValid())
	{
		m_Name				= m_aIndex.get_Name();
		m_IsUnique			= m_aIndex.get_Unique();
        m_IsPrimaryKeyIndex = m_aIndex.get_PrimaryKey();
		m_IsClustered		= m_aIndex.get_Clustered();
	}
}
// -----------------------------------------------------------------------------
void WpADOKey::Create()
{
	HRESULT         hr = -1;
	_ADOKey* pKey = NULL;
	hr = CoCreateInstance(ADOS::CLSID_ADOKEY_25,
						  NULL,
						  CLSCTX_INPROC_SERVER,
						  ADOS::IID_ADOKEY_25,
						  (void**)&pKey );


	if( !FAILED( hr ) )
	{
		operator=( pKey );
		pKey->Release();
	}
}
// -------------------------------------------------------------------------
void OAdoKey::fillPropertyValues()
{
	if(m_aKey.IsValid())
	{
		m_aProps->m_Type			= MapKeyRule(m_aKey.get_Type());
		m_Name			            = m_aKey.get_Name();
		m_aProps->m_ReferencedTable	= m_aKey.get_RelatedTable();
		m_aProps->m_UpdateRule		= MapRule(m_aKey.get_UpdateRule());
		m_aProps->m_DeleteRule		= MapRule(m_aKey.get_DeleteRule());
	}
}
// -------------------------------------------------------------------------
sal_Int32 OAdoKey::MapRule(const RuleEnum& _eNum)
{
        sal_Int32 eNum = KeyRule::NO_ACTION;
	switch(_eNum)
	{
		case adRICascade:
			eNum = KeyRule::CASCADE;
			break;
		case adRISetNull:
            eNum = KeyRule::SET_NULL;
			break;
		case adRINone:
            eNum = KeyRule::NO_ACTION;
			break;
		case adRISetDefault:
            eNum = KeyRule::SET_DEFAULT;
			break;
	}
	return eNum;
}
// -------------------------------------------------------------------------
RuleEnum OAdoKey::Map2Rule(const sal_Int32& _eNum)
{
	RuleEnum eNum = adRINone;
	switch(_eNum)
	{
		case KeyRule::CASCADE:
			eNum = adRICascade;
			break;
        case KeyRule::SET_NULL:
			eNum = adRISetNull;
			break;
        case KeyRule::NO_ACTION:
			eNum = adRINone;
			break;
        case KeyRule::SET_DEFAULT:
			eNum = adRISetDefault;
			break;
	}
	return eNum;
}
// -------------------------------------------------------------------------
sal_Int32 OAdoKey::MapKeyRule(const KeyTypeEnum& _eNum)
{
	sal_Int32 nKeyType = KeyType::PRIMARY;
	switch(_eNum)
	{
		case adKeyPrimary:
			nKeyType = KeyType::PRIMARY;
			break;
		case adKeyForeign:
			nKeyType = KeyType::FOREIGN;
			break;
		case adKeyUnique:
			nKeyType = KeyType::UNIQUE;
			break;
	}
	return nKeyType;
}
// -------------------------------------------------------------------------
KeyTypeEnum OAdoKey::Map2KeyRule(const sal_Int32& _eNum)
{
    KeyTypeEnum eNum( adKeyPrimary );
	switch(_eNum)
	{
		case KeyType::PRIMARY:
			eNum = adKeyPrimary;
			break;
        case KeyType::FOREIGN:
			eNum = adKeyForeign;
			break;
        case KeyType::UNIQUE:
			eNum = adKeyUnique;
			break;
        default:
            OSL_ENSURE( false, "OAdoKey::Map2KeyRule: invalid key type!" );
	}
	return eNum;
}
// -----------------------------------------------------------------------------
void WpADOTable::Create()
{
	HRESULT         hr = -1;
	_ADOTable* pTable = NULL;
	hr = CoCreateInstance(ADOS::CLSID_ADOTABLE_25,
						  NULL,
						  CLSCTX_INPROC_SERVER,
						  ADOS::IID_ADOTABLE_25,
						  (void**)&pTable );


	if( !FAILED( hr ) )
	{
		operator=( pTable );
		pTable->Release();
	}
}
// -------------------------------------------------------------------------
::rtl::OUString WpADOCatalog::GetObjectOwner(const ::rtl::OUString& _rName, ObjectTypeEnum _eNum)
{
	OLEVariant _rVar;
	_rVar.setNoArg();
	OLEString aBSTR;
	OLEString sStr1(_rName);
	pInterface->GetObjectOwner(sStr1,_eNum,_rVar,&aBSTR);
	return aBSTR;
}
// -----------------------------------------------------------------------------
void OAdoTable::fillPropertyValues()
{
	if(m_aTable.IsValid())
	{
		m_Name	= m_aTable.get_Name();
		m_Type	= m_aTable.get_Type();
		{
			WpADOCatalog aCat(m_aTable.get_ParentCatalog());
			if(aCat.IsValid())
				m_CatalogName = aCat.GetObjectOwner(m_aTable.get_Name(),adPermObjTable);
		}
		{
			WpADOProperties aProps = m_aTable.get_Properties();
			if(aProps.IsValid())
				m_Description = OTools::getValue(aProps,::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Description")));
		}
	}
}
// -----------------------------------------------------------------------------
void WpADOUser::Create()
{
	HRESULT         hr = -1;
	_ADOUser* pUser = NULL;
	hr = CoCreateInstance(ADOS::CLSID_ADOUSER_25,
						  NULL,
						  CLSCTX_INPROC_SERVER,
						  ADOS::IID_ADOUSER_25,
						  (void**)&pUser );


	if( !FAILED( hr ) )
	{
		operator=( pUser );
		pUser->Release();
	}
}
// -------------------------------------------------------------------------