/**************************************************************
 * 
 * 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_ucb.hxx"
#include <rtl/uri.hxx>
#include <rtl/ustrbuf.hxx>
#include <osl/file.hxx>

#include "osl/diagnose.h"
#include <com/sun/star/ucb/OpenMode.hpp>
#ifndef _COM_SUN_STAR_BEANS_PROPERTYATTRIBBUTE_HPP_
#include <com/sun/star/beans/PropertyAttribute.hpp>
#endif
#include <com/sun/star/ucb/XProgressHandler.hpp>
#include <com/sun/star/task/XInteractionHandler.hpp>
#include <com/sun/star/io/XActiveDataStreamer.hpp>
#include <com/sun/star/io/XOutputStream.hpp>
#include <com/sun/star/ucb/NumberedSortingInfo.hpp>
#include <com/sun/star/io/XActiveDataSink.hpp>
#include <com/sun/star/beans/PropertyChangeEvent.hpp>
#include <com/sun/star/beans/PropertySetInfoChange.hpp>
#include <com/sun/star/ucb/ContentAction.hpp>
#include <com/sun/star/ucb/NameClash.hpp>
#include "filglob.hxx"
#include "filid.hxx"
#include "filrow.hxx"
#include "bc.hxx"
#include "prov.hxx"
#ifndef _FILERROR_HXX_
#include "filerror.hxx"
#endif
#include "filinsreq.hxx"


using namespace fileaccess;
using namespace com::sun::star;
using namespace com::sun::star::uno;
using namespace com::sun::star::ucb;

// PropertyListeners


typedef cppu::OMultiTypeInterfaceContainerHelperVar< rtl::OUString,hashOUString,equalOUString >
PropertyListeners_impl;

class fileaccess::PropertyListeners
    : public PropertyListeners_impl
{
public:
    PropertyListeners( ::osl::Mutex& aMutex )
        : PropertyListeners_impl( aMutex )
    {
    }
};


/****************************************************************************************/
/*                                                                                      */
/*                    BaseContent                                                       */
/*                                                                                      */
/****************************************************************************************/

////////////////////////////////////////////////////////////////////////////////
// Private Constructor for just inserted Contents

BaseContent::BaseContent( shell* pMyShell,
                          const rtl::OUString& parentName,
                          sal_Bool bFolder )
    : m_pMyShell( pMyShell ),
      m_xContentIdentifier( 0 ),
      m_aUncPath( parentName ),
      m_bFolder( bFolder ),
      m_nState( JustInserted ),
      m_pDisposeEventListeners( 0 ),
      m_pContentEventListeners( 0 ),
      m_pPropertySetInfoChangeListeners( 0 ),
      m_pPropertyListener( 0 )
{
    m_pMyShell->m_pProvider->acquire();
    // No registering, since we have no name
}


////////////////////////////////////////////////////////////////////////////////
// Constructor for full featured Contents

BaseContent::BaseContent( shell* pMyShell,
                          const Reference< XContentIdentifier >& xContentIdentifier,
                          const rtl::OUString& aUncPath )
    : m_pMyShell( pMyShell ),
      m_xContentIdentifier( xContentIdentifier ),
      m_aUncPath( aUncPath ),
      m_bFolder( false ),
      m_nState( FullFeatured ),
      m_pDisposeEventListeners( 0 ),
      m_pContentEventListeners( 0 ),
      m_pPropertySetInfoChangeListeners( 0 ),
      m_pPropertyListener( 0 )
{
    m_pMyShell->m_pProvider->acquire();
    m_pMyShell->registerNotifier( m_aUncPath,this );
    m_pMyShell->insertDefaultProperties( m_aUncPath );
}


BaseContent::~BaseContent( )
{
    if( ( m_nState & FullFeatured ) || ( m_nState & Deleted ) )
    {
        m_pMyShell->deregisterNotifier( m_aUncPath,this );
    }
    m_pMyShell->m_pProvider->release();

    delete m_pDisposeEventListeners;
    delete m_pContentEventListeners;
    delete m_pPropertyListener;
    delete m_pPropertySetInfoChangeListeners;
}


//////////////////////////////////////////////////////////////////////////
// XInterface
//////////////////////////////////////////////////////////////////////////

void SAL_CALL
BaseContent::acquire( void )
    throw()
{
    OWeakObject::acquire();
}


void SAL_CALL
BaseContent::release( void )
    throw()
{
    OWeakObject::release();
}


Any SAL_CALL
BaseContent::queryInterface( const Type& rType )
    throw( RuntimeException )
{
    Any aRet = cppu::queryInterface( rType,
                                     SAL_STATIC_CAST( lang::XComponent*, this ),
                                     SAL_STATIC_CAST( lang::XTypeProvider*, this ),
                                     SAL_STATIC_CAST( lang::XServiceInfo*, this ),
                                     SAL_STATIC_CAST( XCommandProcessor*, this ),
                                     SAL_STATIC_CAST( container::XChild*, this ),
                                     SAL_STATIC_CAST( beans::XPropertiesChangeNotifier*, this ),
                                     SAL_STATIC_CAST( beans::XPropertyContainer*, this ),
                                     SAL_STATIC_CAST( XContentCreator*,this ),
                                     SAL_STATIC_CAST( beans::XPropertySetInfoChangeNotifier*, this ),
                                     SAL_STATIC_CAST( XContent*,this) );
    return aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType );
}




//////////////////////////////////////////////////////////////////////////////////////////
// XComponent
////////////////////////////////////////////////////////////////////////////////////////

void SAL_CALL
BaseContent::addEventListener( const Reference< lang::XEventListener >& Listener )
    throw( RuntimeException )
{
    osl::MutexGuard aGuard( m_aMutex );

    if ( ! m_pDisposeEventListeners )
        m_pDisposeEventListeners =
            new cppu::OInterfaceContainerHelper( m_aEventListenerMutex );

    m_pDisposeEventListeners->addInterface( Listener );
}


void SAL_CALL
BaseContent::removeEventListener( const Reference< lang::XEventListener >& Listener )
    throw( RuntimeException )
{
    osl::MutexGuard aGuard( m_aMutex );

    if ( m_pDisposeEventListeners )
        m_pDisposeEventListeners->removeInterface( Listener );
}


void SAL_CALL
BaseContent::dispose()
    throw( RuntimeException )
{
    lang::EventObject aEvt;
    cppu::OInterfaceContainerHelper* pDisposeEventListeners;
    cppu::OInterfaceContainerHelper* pContentEventListeners;
    cppu::OInterfaceContainerHelper* pPropertySetInfoChangeListeners;
    PropertyListeners* pPropertyListener;

    {
        osl::MutexGuard aGuard( m_aMutex );
        aEvt.Source = static_cast< XContent* >( this );


        pDisposeEventListeners =
            m_pDisposeEventListeners, m_pDisposeEventListeners = 0;

        pContentEventListeners =
            m_pContentEventListeners, m_pContentEventListeners = 0;

        pPropertySetInfoChangeListeners =
            m_pPropertySetInfoChangeListeners,
            m_pPropertySetInfoChangeListeners = 0;

        pPropertyListener =
            m_pPropertyListener, m_pPropertyListener = 0;
    }

    if ( pDisposeEventListeners && pDisposeEventListeners->getLength() )
        pDisposeEventListeners->disposeAndClear( aEvt );

    if ( pContentEventListeners && pContentEventListeners->getLength() )
        pContentEventListeners->disposeAndClear( aEvt );

    if( pPropertyListener )
        pPropertyListener->disposeAndClear( aEvt );

    if( pPropertySetInfoChangeListeners )
        pPropertySetInfoChangeListeners->disposeAndClear( aEvt );

    delete pDisposeEventListeners;
    delete pContentEventListeners;
    delete pPropertyListener;
    delete pPropertySetInfoChangeListeners;
}



//////////////////////////////////////////////////////////////////////////////////////////
//  XServiceInfo
//////////////////////////////////////////////////////////////////////////////////////////

rtl::OUString SAL_CALL
BaseContent::getImplementationName()
    throw( RuntimeException)
{
    return rtl::OUString::createFromAscii( "com.sun.star.comp.ucb.FileContent" );
}



sal_Bool SAL_CALL
BaseContent::supportsService( const rtl::OUString& ServiceName )
    throw( RuntimeException)
{
    if( ServiceName.compareToAscii( "com.sun.star.ucb.FileContent" ) == 0 )
        return true;
    else
        return false;
}



Sequence< rtl::OUString > SAL_CALL
BaseContent::getSupportedServiceNames()
    throw( RuntimeException )
{
    Sequence< rtl::OUString > ret( 1 );
    ret[0] = rtl::OUString::createFromAscii( "com.sun.star.ucb.FileContent" );
    return ret;
}



//////////////////////////////////////////////////////////////////////////////////////////
//  XTypeProvider
//////////////////////////////////////////////////////////////////////////////////////////

XTYPEPROVIDER_IMPL_10( BaseContent,
                       lang::XComponent,
                       lang::XTypeProvider,
                       lang::XServiceInfo,
                       XCommandProcessor,
                       XContentCreator,
                       XContent,
                       container::XChild,
                       beans::XPropertiesChangeNotifier,
                       beans::XPropertyContainer,
                       beans::XPropertySetInfoChangeNotifier )


//////////////////////////////////////////////////////////////////////////////////////////
//  XCommandProcessor
//////////////////////////////////////////////////////////////////////////////////////////

sal_Int32 SAL_CALL
BaseContent::createCommandIdentifier( void )
    throw( RuntimeException )
{
    return m_pMyShell->getCommandId();
}


void SAL_CALL
BaseContent::abort( sal_Int32 CommandId )
    throw( RuntimeException )
{
    m_pMyShell->abort( CommandId );
}


Any SAL_CALL
BaseContent::execute( const Command& aCommand,
                      sal_Int32 CommandId,
                      const Reference< XCommandEnvironment >& Environment )
    throw( Exception,
           CommandAbortedException,
           RuntimeException )
{
    if( ! CommandId )
        // A Command with commandid zero cannot be aborted
        CommandId = createCommandIdentifier();

    m_pMyShell->startTask( CommandId,
                           Environment );

    Any aAny;

    if( ! aCommand.Name.compareToAscii( "getPropertySetInfo" ) )  // No exceptions
    {
        aAny <<= getPropertySetInfo( CommandId );
    }
    else if( ! aCommand.Name.compareToAscii( "getCommandInfo" ) )  // no exceptions
    {
        aAny <<= getCommandInfo();
    }
    else if( ! aCommand.Name.compareToAscii( "setPropertyValues" ) )
    {
        Sequence< beans::PropertyValue > sPropertyValues;

        if( ! ( aCommand.Argument >>= sPropertyValues ) )
            m_pMyShell->installError( CommandId,
                                      TASKHANDLING_WRONG_SETPROPERTYVALUES_ARGUMENT );
        else
            aAny <<= setPropertyValues( CommandId,sPropertyValues );  // calls endTask by itself
    }
    else if( ! aCommand.Name.compareToAscii( "getPropertyValues" ) )
    {
        Sequence< beans::Property > ListOfRequestedProperties;

        if( ! ( aCommand.Argument >>= ListOfRequestedProperties ) )
            m_pMyShell->installError( CommandId,
                                      TASKHANDLING_WRONG_GETPROPERTYVALUES_ARGUMENT );
        else
            aAny <<= getPropertyValues( CommandId,
                                        ListOfRequestedProperties );
    }
    else if( ! aCommand.Name.compareToAscii( "open" ) )
    {
        OpenCommandArgument2 aOpenArgument;
        if( ! ( aCommand.Argument >>= aOpenArgument ) )
            m_pMyShell->installError( CommandId,
                                      TASKHANDLING_WRONG_OPEN_ARGUMENT );
        else
        {
            Reference< XDynamicResultSet > result = open( CommandId,aOpenArgument );
            if( result.is() )
                aAny <<= result;
        }
    }
    else if( ! aCommand.Name.compareToAscii( "delete" ) )
    {
        if( ! aCommand.Argument.has< sal_Bool >() )
            m_pMyShell->installError( CommandId,
                                      TASKHANDLING_WRONG_DELETE_ARGUMENT );
        else
            deleteContent( CommandId );
    }
    else if( ! aCommand.Name.compareToAscii( "transfer" ) )
    {
        TransferInfo aTransferInfo;
        if( ! ( aCommand.Argument >>= aTransferInfo ) )
            m_pMyShell->installError( CommandId,
                                      TASKHANDLING_WRONG_TRANSFER_ARGUMENT );
        else
            transfer( CommandId, aTransferInfo );
    }
    else if( ! aCommand.Name.compareToAscii( "insert" ) )
    {
        InsertCommandArgument aInsertArgument;
        if( ! ( aCommand.Argument >>= aInsertArgument ) )
            m_pMyShell->installError( CommandId,
                                      TASKHANDLING_WRONG_INSERT_ARGUMENT );
        else
            insert( CommandId,aInsertArgument );
    }
    else if( ! aCommand.Name.compareToAscii( "getCasePreservingURL" ) )
    {
        Sequence< beans::Property > seq(1);
        seq[0] = beans::Property(
            rtl::OUString::createFromAscii("CasePreservingURL"),
            -1,
            getCppuType( static_cast< sal_Bool* >(0) ),
            0 );
        Reference< sdbc::XRow > xRow = getPropertyValues( CommandId,seq );
        rtl::OUString CasePreservingURL = xRow->getString(1);
        if(!xRow->wasNull())
            aAny <<= CasePreservingURL;
    }
    else if( ! aCommand.Name.compareToAscii( "createNewContent" ) )
    {
        ucb::ContentInfo aArg;
        if ( !( aCommand.Argument >>= aArg ) )
            m_pMyShell->installError( CommandId,
                                      TASKHANDLING_WRONG_CREATENEWCONTENT_ARGUMENT );
        else
            aAny <<= createNewContent( aArg );
    }
    else
        m_pMyShell->installError( CommandId,
                                  TASKHANDLER_UNSUPPORTED_COMMAND );


    // This is the only function allowed to throw an exception
    endTask( CommandId );

    return aAny;
}



void SAL_CALL
BaseContent::addPropertiesChangeListener(
    const Sequence< rtl::OUString >& PropertyNames,
    const Reference< beans::XPropertiesChangeListener >& Listener )
    throw( RuntimeException )
{
    if( ! Listener.is() )
        return;

    osl::MutexGuard aGuard( m_aMutex );

    if( ! m_pPropertyListener )
        m_pPropertyListener = new PropertyListeners( m_aEventListenerMutex );


    if( PropertyNames.getLength() == 0 )
        m_pPropertyListener->addInterface( rtl::OUString(),Listener );
    else
    {
        Reference< beans::XPropertySetInfo > xProp = m_pMyShell->info_p( m_aUncPath );
        for( sal_Int32 i = 0; i < PropertyNames.getLength(); ++i )
            if( xProp->hasPropertyByName( PropertyNames[i] ) )
                m_pPropertyListener->addInterface( PropertyNames[i],Listener );
    }
}


void SAL_CALL
BaseContent::removePropertiesChangeListener( const Sequence< rtl::OUString >& PropertyNames,
                                             const Reference< beans::XPropertiesChangeListener >& Listener )
    throw( RuntimeException )
{
    if( ! Listener.is() )
        return;

    osl::MutexGuard aGuard( m_aMutex );

    if( ! m_pPropertyListener )
        return;

    for( sal_Int32 i = 0; i < PropertyNames.getLength(); ++i )
        m_pPropertyListener->removeInterface( PropertyNames[i],Listener );

    m_pPropertyListener->removeInterface( rtl::OUString(), Listener );
}


/////////////////////////////////////////////////////////////////////////////////////////
// XContent
/////////////////////////////////////////////////////////////////////////////////////////

Reference< ucb::XContentIdentifier > SAL_CALL
BaseContent::getIdentifier()
    throw( RuntimeException )
{
    return m_xContentIdentifier;
}


rtl::OUString SAL_CALL
BaseContent::getContentType()
    throw( RuntimeException )
{
    if( !( m_nState & Deleted ) )
    {
        if( m_nState & JustInserted )
        {
            if ( m_bFolder )
                return m_pMyShell->FolderContentType;
            else
                return m_pMyShell->FileContentType;
        }
        else
        {
            try
            {
                // Who am I ?
                Sequence< beans::Property > seq(1);
                seq[0] = beans::Property( rtl::OUString::createFromAscii("IsDocument"),
                                          -1,
                                          getCppuType( static_cast< sal_Bool* >(0) ),
                                          0 );
                Reference< sdbc::XRow > xRow = getPropertyValues( -1,seq );
                sal_Bool IsDocument = xRow->getBoolean( 1 );

                if ( !xRow->wasNull() )
                {
                    if ( IsDocument )
                        return m_pMyShell->FileContentType;
                    else
                        return m_pMyShell->FolderContentType;
                }
                else
                {
                    OSL_ENSURE( false,
                                "BaseContent::getContentType - Property value was null!" );
                }
            }
            catch ( sdbc::SQLException const & )
            {
                OSL_ENSURE( false,
                            "BaseContent::getContentType - Caught SQLException!" );
            }
        }
    }

    return rtl::OUString();
}



void SAL_CALL
BaseContent::addContentEventListener(
    const Reference< XContentEventListener >& Listener )
    throw( RuntimeException )
{
    osl::MutexGuard aGuard( m_aMutex );

    if ( ! m_pContentEventListeners )
        m_pContentEventListeners =
            new cppu::OInterfaceContainerHelper( m_aEventListenerMutex );


    m_pContentEventListeners->addInterface( Listener );
}


void SAL_CALL
BaseContent::removeContentEventListener(
    const Reference< XContentEventListener >& Listener )
    throw( RuntimeException )
{
    osl::MutexGuard aGuard( m_aMutex );

    if ( m_pContentEventListeners )
        m_pContentEventListeners->removeInterface( Listener );
}



////////////////////////////////////////////////////////////////////////////////
// XPropertyContainer
////////////////////////////////////////////////////////////////////////////////


void SAL_CALL
BaseContent::addProperty(
    const rtl::OUString& Name,
    sal_Int16 Attributes,
    const Any& DefaultValue )
    throw( beans::PropertyExistException,
           beans::IllegalTypeException,
           lang::IllegalArgumentException,
           RuntimeException)
{
    if( ( m_nState & JustInserted ) || ( m_nState & Deleted ) || Name == rtl::OUString() )
    {
        throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 0 );
    }

    m_pMyShell->associate( m_aUncPath,Name,DefaultValue,Attributes );
}


void SAL_CALL
BaseContent::removeProperty(
    const rtl::OUString& Name )
    throw( beans::UnknownPropertyException,
           beans::NotRemoveableException,
           RuntimeException)
{

    if( m_nState & Deleted )
        throw beans::UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );

    m_pMyShell->deassociate( m_aUncPath, Name );
}

////////////////////////////////////////////////////////////////////////////////
// XContentCreator
////////////////////////////////////////////////////////////////////////////////

Sequence< ContentInfo > SAL_CALL
BaseContent::queryCreatableContentsInfo(
    void )
    throw( RuntimeException )
{
    return m_pMyShell->queryCreatableContentsInfo();
}


Reference< XContent > SAL_CALL
BaseContent::createNewContent(
    const ContentInfo& Info )
    throw( RuntimeException )
{
    // Check type.
    if ( !Info.Type.getLength() )
        return Reference< XContent >();

    sal_Bool bFolder
        = ( Info.Type.compareTo( m_pMyShell->FolderContentType ) == 0 );
    if ( !bFolder )
    {
        if ( Info.Type.compareTo( m_pMyShell->FileContentType ) != 0 )
        {
            // Neither folder nor file to create!
            return Reference< XContent >();
        }
    }

    // Who am I ?
    sal_Bool IsDocument = false;

    try
    {
        Sequence< beans::Property > seq(1);
        seq[0] = beans::Property( rtl::OUString::createFromAscii("IsDocument"),
                                  -1,
                                  getCppuType( static_cast< sal_Bool* >(0) ),
                                  0 );
        Reference< sdbc::XRow > xRow = getPropertyValues( -1,seq );
        IsDocument = xRow->getBoolean( 1 );

        if ( xRow->wasNull() )
        {
            IsDocument = false;
//              OSL_ENSURE( false,
//                          "BaseContent::createNewContent - Property value was null!" );
//              return Reference< XContent >();
        }
    }
    catch ( sdbc::SQLException const & )
    {
        OSL_ENSURE( false,
                    "BaseContent::createNewContent - Caught SQLException!" );
        return Reference< XContent >();
    }

    rtl::OUString dstUncPath;

    if( IsDocument )
    {
        // KSO: Why is a document a XContentCreator? This is quite unusual.
        dstUncPath = getParentName( m_aUncPath );
    }
    else
        dstUncPath = m_aUncPath;

    BaseContent* p = new BaseContent( m_pMyShell, dstUncPath, bFolder );
    return Reference< XContent >( p );
}


////////////////////////////////////////////////////////////////////////////////
// XPropertySetInfoChangeNotifier
////////////////////////////////////////////////////////////////////////////////


void SAL_CALL
BaseContent::addPropertySetInfoChangeListener(
    const Reference< beans::XPropertySetInfoChangeListener >& Listener )
    throw( RuntimeException )
{
    osl::MutexGuard aGuard( m_aMutex );
    if( ! m_pPropertySetInfoChangeListeners )
        m_pPropertySetInfoChangeListeners = new cppu::OInterfaceContainerHelper( m_aEventListenerMutex );

    m_pPropertySetInfoChangeListeners->addInterface( Listener );
}


void SAL_CALL
BaseContent::removePropertySetInfoChangeListener(
    const Reference< beans::XPropertySetInfoChangeListener >& Listener )
    throw( RuntimeException )
{
    osl::MutexGuard aGuard( m_aMutex );

    if( m_pPropertySetInfoChangeListeners )
        m_pPropertySetInfoChangeListeners->removeInterface( Listener );
}


////////////////////////////////////////////////////////////////////////////////
// XChild
////////////////////////////////////////////////////////////////////////////////

Reference< XInterface > SAL_CALL
BaseContent::getParent(
    void )
    throw( RuntimeException )
{
    rtl::OUString ParentUnq = getParentName( m_aUncPath );
    rtl::OUString ParentUrl;


    sal_Bool err = m_pMyShell->getUrlFromUnq( ParentUnq, ParentUrl );
    if( err )
        return Reference< XInterface >( 0 );

    FileContentIdentifier* p = new FileContentIdentifier( m_pMyShell,ParentUnq );
    Reference< XContentIdentifier > Identifier( p );

    try
    {
        Reference< XContent > content = m_pMyShell->m_pProvider->queryContent( Identifier );
        return Reference<XInterface>(content,UNO_QUERY);
    }
    catch( IllegalIdentifierException )
    {
        return Reference< XInterface >();
    }
}


void SAL_CALL
BaseContent::setParent(
    const Reference< XInterface >& )
    throw( lang::NoSupportException,
           RuntimeException)
{
    throw lang::NoSupportException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
}


//////////////////////////////////////////////////////////////////////////////////////////
// Private Methods
//////////////////////////////////////////////////////////////////////////////////////////


Reference< XCommandInfo > SAL_CALL
BaseContent::getCommandInfo()
    throw( RuntimeException )
{
    if( m_nState & Deleted )
        return Reference< XCommandInfo >();

    return m_pMyShell->info_c();
}


Reference< beans::XPropertySetInfo > SAL_CALL
BaseContent::getPropertySetInfo(
    sal_Int32 )
    throw( RuntimeException )
{
    if( m_nState & Deleted )
        return Reference< beans::XPropertySetInfo >();

    return m_pMyShell->info_p( m_aUncPath );
}




Reference< sdbc::XRow > SAL_CALL
BaseContent::getPropertyValues(
    sal_Int32 nMyCommandIdentifier,
    const Sequence< beans::Property >& PropertySet )
    throw( RuntimeException )
{
    sal_Int32 nProps = PropertySet.getLength();
    if ( !nProps )
        return Reference< sdbc::XRow >();

    if( m_nState & Deleted )
    {
        Sequence< Any > aValues( nProps );
        return Reference< sdbc::XRow >( new XRow_impl( m_pMyShell, aValues ) );
    }

    if( m_nState & JustInserted )
    {
        Sequence< Any > aValues( nProps );
        Any* pValues = aValues.getArray();

        const beans::Property* pProps = PropertySet.getConstArray();

        for ( sal_Int32 n = 0; n < nProps; ++n )
        {
            const beans::Property& rProp = pProps[ n ];
            Any& rValue = pValues[ n ];

            if( rProp.Name.compareToAscii( "ContentType" ) == 0 )
            {
                rValue <<= m_bFolder ? m_pMyShell->FolderContentType
                    : m_pMyShell->FileContentType;
            }
            else if( rProp.Name.compareToAscii( "IsFolder" ) == 0 )
            {
                rValue <<= m_bFolder;
            }
            else if( rProp.Name.compareToAscii( "IsDocument" ) == 0 )
            {
                rValue <<= sal_Bool( !m_bFolder );
            }
        }

        return Reference< sdbc::XRow >(
            new XRow_impl( m_pMyShell, aValues ) );
    }

    return m_pMyShell->getv( nMyCommandIdentifier,
                             m_aUncPath,
                             PropertySet );
}


Sequence< Any > SAL_CALL
BaseContent::setPropertyValues(
    sal_Int32 nMyCommandIdentifier,
    const Sequence< beans::PropertyValue >& Values )
    throw()
{
    if( m_nState & Deleted )
    {   //  To do
        return Sequence< Any >( Values.getLength() );
    }

    const rtl::OUString Title = rtl::OUString::createFromAscii( "Title" );

    // Special handling for files which have to be inserted
    if( m_nState & JustInserted )
    {
        for( sal_Int32 i = 0; i < Values.getLength(); ++i )
        {
            if( Values[i].Name == Title )
            {
                rtl::OUString NewTitle;
                if( Values[i].Value >>= NewTitle )
                {
                    if ( m_nState & NameForInsertionSet )
                    {
                        // User wants to set another Title before "insert".
                        // m_aUncPath contains previous own URI.

                        sal_Int32 nLastSlash = m_aUncPath.lastIndexOf( '/' );
                        bool bTrailingSlash = false;
                        if ( nLastSlash == m_aUncPath.getLength() - 1 )
                        {
                            bTrailingSlash = true;
                            nLastSlash
                                = m_aUncPath.lastIndexOf( '/', nLastSlash );
                        }

                        OSL_ENSURE( nLastSlash != -1,
                                    "BaseContent::setPropertyValues: "
                                    "Invalid URL!" );

                        rtl::OUStringBuffer aBuf(
                            m_aUncPath.copy( 0, nLastSlash + 1 ) );

                        if ( NewTitle.getLength() > 0 )
                        {
                            aBuf.append( NewTitle );
                            if ( bTrailingSlash )
                                aBuf.append( sal_Unicode( '/' ) );
                        }
                        else
                        {
                            m_nState &= ~NameForInsertionSet;
                        }

                        m_aUncPath = aBuf.makeStringAndClear();
                    }
                    else
                    {
                        if ( NewTitle.getLength() > 0 )
                        {
                            // Initial Title before "insert".
                            // m_aUncPath contains parent's URI.

                            if( m_aUncPath.lastIndexOf( sal_Unicode('/') ) != m_aUncPath.getLength() - 1 )
                                m_aUncPath += rtl::OUString::createFromAscii("/");

                            m_aUncPath += rtl::Uri::encode( NewTitle,
                                                            rtl_UriCharClassPchar,
                                                            rtl_UriEncodeIgnoreEscapes,
                                                            RTL_TEXTENCODING_UTF8 );
                            m_nState |= NameForInsertionSet;
                        }
                    }
                }
            }
        }

        return Sequence< Any >( Values.getLength() );
    }
    else
    {
        Sequence< Any > ret = m_pMyShell->setv( m_aUncPath,  // Does not handle Title
                                                Values );

        // Special handling Title: Setting Title is equivalent to a renaming of the underlying file
        for( sal_Int32 i = 0; i < Values.getLength(); ++i )
        {
            if( Values[i].Name != Title )
                continue;                  // handled by setv

            rtl::OUString NewTitle;
            if( !( Values[i].Value >>= NewTitle ) )
            {
                ret[i] <<= beans::IllegalTypeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
                break;
            }
            else if( ! NewTitle.getLength() )
            {
                ret[i] <<= lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 0 );
                break;
            }


            rtl::OUString aDstName = getParentName( m_aUncPath );
            if( aDstName.lastIndexOf( sal_Unicode('/') ) != aDstName.getLength() - 1 )
                aDstName += rtl::OUString::createFromAscii("/");

            aDstName += rtl::Uri::encode( NewTitle,
                                          rtl_UriCharClassPchar,
                                          rtl_UriEncodeIgnoreEscapes,
                                          RTL_TEXTENCODING_UTF8 );

            m_pMyShell->move( nMyCommandIdentifier,     // move notifies the childs also;
                              m_aUncPath,
                              aDstName,
                              NameClash::KEEP );

            try
            {
                endTask( nMyCommandIdentifier );
            }
            catch( const Exception& e )
            {
                ret[i] <<= e;
            }

            // NameChanges come back trough a ContentEvent
            break; // only handling Title
        } // end for

        return ret;
    }
}



Reference< XDynamicResultSet > SAL_CALL
BaseContent::open(
    sal_Int32 nMyCommandIdentifier,
    const OpenCommandArgument2& aCommandArgument )
    throw()
{
    Reference< XDynamicResultSet > retValue( 0 );

    if( ( m_nState & Deleted ) )
    {
        m_pMyShell->installError( nMyCommandIdentifier,
                                  TASKHANDLING_DELETED_STATE_IN_OPEN_COMMAND );
    }
    else if( m_nState & JustInserted )
    {
        m_pMyShell->installError( nMyCommandIdentifier,
                                  TASKHANDLING_INSERTED_STATE_IN_OPEN_COMMAND );
    }
    else
    {
        if( aCommandArgument.Mode == OpenMode::DOCUMENT ||
            aCommandArgument.Mode == OpenMode::DOCUMENT_SHARE_DENY_NONE )

        {
            Reference< io::XOutputStream > outputStream( aCommandArgument.Sink,UNO_QUERY );
            if( outputStream.is() )
            {
                m_pMyShell->page( nMyCommandIdentifier,
                                  m_aUncPath,
                                  outputStream );
            }

            sal_Bool bLock = ( aCommandArgument.Mode != OpenMode::DOCUMENT_SHARE_DENY_NONE );

            Reference< io::XActiveDataSink > activeDataSink( aCommandArgument.Sink,UNO_QUERY );
            if( activeDataSink.is() )
            {
                activeDataSink->setInputStream( m_pMyShell->open( nMyCommandIdentifier,
                                                                  m_aUncPath,
                                                                  bLock ) );
            }

            Reference< io::XActiveDataStreamer > activeDataStreamer( aCommandArgument.Sink,UNO_QUERY );
            if( activeDataStreamer.is() )
            {
                activeDataStreamer->setStream( m_pMyShell->open_rw( nMyCommandIdentifier,
                                                                    m_aUncPath,
                                                                    bLock ) );
            }
        }
        else if ( aCommandArgument.Mode == OpenMode::ALL        ||
                  aCommandArgument.Mode == OpenMode::FOLDERS    ||
                  aCommandArgument.Mode == OpenMode::DOCUMENTS )
        {
            retValue = m_pMyShell->ls( nMyCommandIdentifier,
                                       m_aUncPath,
                                       aCommandArgument.Mode,
                                       aCommandArgument.Properties,
                                       aCommandArgument.SortingInfo );
        }
//          else if(  aCommandArgument.Mode ==
//                    OpenMode::DOCUMENT_SHARE_DENY_NONE  ||
//                    aCommandArgument.Mode ==
//                    OpenMode::DOCUMENT_SHARE_DENY_WRITE )
//              m_pMyShell->installError( nMyCommandIdentifier,
//                                        TASKHANDLING_UNSUPPORTED_OPEN_MODE,
//                                        aCommandArgument.Mode);
        else
            m_pMyShell->installError( nMyCommandIdentifier,
                                      TASKHANDLING_UNSUPPORTED_OPEN_MODE,
                                      aCommandArgument.Mode);
    }

    return retValue;
}



void SAL_CALL
BaseContent::deleteContent( sal_Int32 nMyCommandIdentifier )
    throw()
{
    if( m_nState & Deleted )
        return;

    if( m_pMyShell->remove( nMyCommandIdentifier,m_aUncPath ) )
    {
        osl::MutexGuard aGuard( m_aMutex );
        m_nState |= Deleted;
    }
}



void SAL_CALL
BaseContent::transfer( sal_Int32 nMyCommandIdentifier,
                       const TransferInfo& aTransferInfo )
    throw()
{
    if( m_nState & Deleted )
        return;

    if( aTransferInfo.SourceURL.compareToAscii( "file:",5 ) != 0 )
    {
        m_pMyShell->installError( nMyCommandIdentifier,
                                  TASKHANDLING_TRANSFER_INVALIDSCHEME );
        return;
    }

    rtl::OUString srcUnc;
    if( m_pMyShell->getUnqFromUrl( aTransferInfo.SourceURL,srcUnc ) )
    {
        m_pMyShell->installError( nMyCommandIdentifier,
                                  TASKHANDLING_TRANSFER_INVALIDURL );
        return;
    }

    rtl::OUString srcUncPath = srcUnc;

    // Determine the new title !
    rtl::OUString NewTitle;
    if( aTransferInfo.NewTitle.getLength() )
        NewTitle = rtl::Uri::encode( aTransferInfo.NewTitle,
                                     rtl_UriCharClassPchar,
                                     rtl_UriEncodeIgnoreEscapes,
                                     RTL_TEXTENCODING_UTF8 );
    else
        NewTitle = srcUncPath.copy( 1 + srcUncPath.lastIndexOf( sal_Unicode('/') ) );

    // Is destination a document or a folder ?
    Sequence< beans::Property > seq(1);
    seq[0] = beans::Property( rtl::OUString::createFromAscii("IsDocument"),
                              -1,
                              getCppuType( static_cast< sal_Bool* >(0) ),
                              0 );
    Reference< sdbc::XRow > xRow = getPropertyValues( nMyCommandIdentifier,seq );
    sal_Bool IsDocument = xRow->getBoolean( 1 );
    if( xRow->wasNull() )
    {   // Destination file type could not be determined
        m_pMyShell->installError( nMyCommandIdentifier,
                                  TASKHANDLING_TRANSFER_DESTFILETYPE );
        return;
    }

    rtl::OUString dstUncPath;
    if( IsDocument )
    {   // as sibling
        sal_Int32 lastSlash = m_aUncPath.lastIndexOf( sal_Unicode('/') );
        dstUncPath = m_aUncPath.copy(0,lastSlash );
    }
    else
        // as child
        dstUncPath = m_aUncPath;

    dstUncPath += ( rtl::OUString::createFromAscii( "/" ) + NewTitle );

    sal_Int32 NameClash = aTransferInfo.NameClash;

    if( aTransferInfo.MoveData )
        m_pMyShell->move( nMyCommandIdentifier,srcUncPath,dstUncPath,NameClash );
    else
        m_pMyShell->copy( nMyCommandIdentifier,srcUncPath,dstUncPath,NameClash );
}




void SAL_CALL BaseContent::insert( sal_Int32 nMyCommandIdentifier,
                                   const InsertCommandArgument& aInsertArgument )
    throw()
{
    if( m_nState & FullFeatured )
    {
        m_pMyShell->write( nMyCommandIdentifier,
                           m_aUncPath,
                           aInsertArgument.ReplaceExisting,
                           aInsertArgument.Data );
        return;
    }

    if( ! ( m_nState & JustInserted ) )
    {
        m_pMyShell->installError( nMyCommandIdentifier,
                                  TASKHANDLING_NOFRESHINSERT_IN_INSERT_COMMAND );
        return;
    }

    // Inserts the content, which has the flag m_bIsFresh

    if ( !m_nState | !NameForInsertionSet )
    {
        m_pMyShell->installError( nMyCommandIdentifier,
                                  TASKHANDLING_NONAMESET_INSERT_COMMAND );
        return;
    }

    // Inserting a document or a file?
    sal_Bool bDocument = false;

    Sequence< beans::Property > seq(1);
    seq[0] = beans::Property( rtl::OUString::createFromAscii("IsDocument"),
                              -1,
                              getCppuType( static_cast< sal_Bool* >(0) ),
                              0 );

    Reference< sdbc::XRow > xRow = getPropertyValues( -1,seq );

    bool contentTypeSet = true;  // is set to false, if contentType not set
    try
    {
        bDocument = xRow->getBoolean( 1 );
        if( xRow->wasNull() )
            contentTypeSet = false;

    }
    catch ( sdbc::SQLException const & )
    {
        OSL_ENSURE( false,
                    "BaseContent::insert - Caught SQLException!" );
        contentTypeSet = false;
    }

    if( ! contentTypeSet )
    {
        m_pMyShell->installError( nMyCommandIdentifier,
                                  TASKHANDLING_NOCONTENTTYPE_INSERT_COMMAND );
        return;
    }


    sal_Bool success = false;
    if( bDocument )
        success = m_pMyShell->mkfil( nMyCommandIdentifier,
                                     m_aUncPath,
                                     aInsertArgument.ReplaceExisting,
                                     aInsertArgument.Data );
    else
    {
        while( ! success )
        {
            success = m_pMyShell->mkdir( nMyCommandIdentifier,
                                         m_aUncPath,
                                         aInsertArgument.ReplaceExisting );
            if( success )
                break;

            XInteractionRequestImpl *aRequestImpl =
                new XInteractionRequestImpl(
                    rtl::Uri::decode(
                        getTitle(m_aUncPath),
                        rtl_UriDecodeWithCharset,
                        RTL_TEXTENCODING_UTF8),
                    (cppu::OWeakObject*)this,
                    m_pMyShell,nMyCommandIdentifier);
            uno::Reference< task::XInteractionRequest > aReq( aRequestImpl );

            m_pMyShell->handleTask( nMyCommandIdentifier,aReq );
            if(  aRequestImpl->aborted() ||
                 !aRequestImpl->newName().getLength() )
                // means aborting
                break;

            // determine new uncpath
            m_pMyShell->clearError( nMyCommandIdentifier );
            m_aUncPath = getParentName( m_aUncPath );
            if( m_aUncPath.lastIndexOf( sal_Unicode('/') ) != m_aUncPath.getLength() - 1 )
                m_aUncPath += rtl::OUString::createFromAscii("/");

            m_aUncPath += rtl::Uri::encode( aRequestImpl->newName(),
                                            rtl_UriCharClassPchar,
                                            rtl_UriEncodeIgnoreEscapes,
                                            RTL_TEXTENCODING_UTF8 );
        }
    }

    if ( ! success )
        return;

    FileContentIdentifier* p = new FileContentIdentifier( m_pMyShell,m_aUncPath );
    m_xContentIdentifier = Reference< XContentIdentifier >( p );

    m_pMyShell->registerNotifier( m_aUncPath,this );
    m_pMyShell->insertDefaultProperties( m_aUncPath );

    osl::MutexGuard aGuard( m_aMutex );
    m_nState = FullFeatured;
}



void SAL_CALL BaseContent::endTask( sal_Int32 CommandId )
{
    // This is the only function allowed to throw an exception
    m_pMyShell->endTask( CommandId,m_aUncPath,this );
}



ContentEventNotifier*
BaseContent::cDEL( void )
{
    osl::MutexGuard aGuard( m_aMutex );

    m_nState |= Deleted;

    ContentEventNotifier* p;
    if( m_pContentEventListeners )
        p = new ContentEventNotifier( m_pMyShell,
                                      this,
                                      m_xContentIdentifier,
                                      m_pContentEventListeners->getElements() );
    else
        p = 0;

    return p;
}


ContentEventNotifier*
BaseContent::cEXC( const rtl::OUString aNewName )
{
    osl::MutexGuard aGuard( m_aMutex );

    Reference< XContentIdentifier > xOldRef = m_xContentIdentifier;
    m_aUncPath = aNewName;
    FileContentIdentifier* pp = new FileContentIdentifier( m_pMyShell,aNewName );
    m_xContentIdentifier = Reference< XContentIdentifier >( pp );

    ContentEventNotifier* p = 0;
    if( m_pContentEventListeners )
        p = new ContentEventNotifier( m_pMyShell,
                                      this,
                                      m_xContentIdentifier,
                                      xOldRef,
                                      m_pContentEventListeners->getElements() );

    return p;
}


ContentEventNotifier*
BaseContent::cCEL( void )
{
    osl::MutexGuard aGuard( m_aMutex );
    ContentEventNotifier* p = 0;
    if( m_pContentEventListeners )
        p = new ContentEventNotifier( m_pMyShell,
                                      this,
                                      m_xContentIdentifier,
                                      m_pContentEventListeners->getElements() );

    return p;
}

PropertySetInfoChangeNotifier*
BaseContent::cPSL( void )
{
    osl::MutexGuard aGuard( m_aMutex );
    PropertySetInfoChangeNotifier* p = 0;
    if( m_pPropertySetInfoChangeListeners  )
        p = new PropertySetInfoChangeNotifier( m_pMyShell,
                                               this,
                                               m_xContentIdentifier,
                                               m_pPropertySetInfoChangeListeners->getElements() );

    return p;
}



PropertyChangeNotifier*
BaseContent::cPCL( void )
{
    osl::MutexGuard aGuard( m_aMutex );

    Sequence< rtl::OUString > seqNames;

    if( m_pPropertyListener )
        seqNames = m_pPropertyListener->getContainedTypes();

    PropertyChangeNotifier* p = 0;

    sal_Int32 length = seqNames.getLength();

    if( length )
    {
        ListenerMap* listener = new ListenerMap();
        for( sal_Int32 i = 0; i < length; ++i )
        {
            (*listener)[seqNames[i]] = m_pPropertyListener->getContainer( seqNames[i] )->getElements();
        }

        p = new PropertyChangeNotifier( m_pMyShell,
                                        this,
                                        m_xContentIdentifier,
                                        listener );
    }

    return p;
}


rtl::OUString BaseContent::getKey( void )
{
    return m_aUncPath;
}
