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



#ifndef __FRAMEWORK_SERVICES_SUBSTPATHVARS_HXX_
#define __FRAMEWORK_SERVICES_SUBSTPATHVARS_HXX_

/** Attention: stl headers must(!) be included at first. Otherwhise it can make trouble
               with solaris headers ...
*/
#include <vector>
#include <list>
#include <hash_map>

//_________________________________________________________________________________________________________________
//      my own includes
//_________________________________________________________________________________________________________________
#include <threadhelp/threadhelpbase.hxx>
#include <macros/generic.hxx>
#include <macros/xinterface.hxx>
#include <macros/xtypeprovider.hxx>
#include <macros/xserviceinfo.hxx>
#include <stdtypes.h>

//_________________________________________________________________________________________________________________
//      interface includes
//_________________________________________________________________________________________________________________
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XTypeProvider.hpp>
#include <com/sun/star/container/NoSuchElementException.hpp>
#include <com/sun/star/util/XStringSubstitution.hpp>

//_________________________________________________________________________________________________________________
//      other includes
//_________________________________________________________________________________________________________________
#include <cppuhelper/implbase2.hxx>
#include <rtl/ustring.hxx>
#include <unotools/configitem.hxx>
#include <tools/link.hxx>
#include <i18npool/lang.h>

namespace framework
{

// Must be zero value based
enum EnvironmentType
{
        ET_HOST = 0             ,
        ET_YPDOMAIN             ,
        ET_DNSDOMAIN    ,
        ET_NTDOMAIN             ,
        ET_OS                   ,
        ET_UNKNOWN              ,
        ET_COUNT
};

// Must be zero value based
enum OperatingSystem
{
        OS_WINDOWS = 0,
        OS_UNIX         ,
        OS_SOLARIS      ,
        OS_LINUX        ,
        OS_UNKNOWN      ,
        OS_COUNT
};

struct SubstituteRule
{
    SubstituteRule() {}
    SubstituteRule( const rtl::OUString& aVarName,
                    const rtl::OUString& aValue,
                    const com::sun::star::uno::Any& aVal,
                    EnvironmentType aType ) :
        aSubstVariable( aVarName ), aSubstValue( aValue ), aEnvValue( aVal ), aEnvType( aType ) {}

    rtl::OUString            aSubstVariable;
    rtl::OUString            aSubstValue;
    com::sun::star::uno::Any aEnvValue;
    EnvironmentType          aEnvType;
};

struct SubstitutePathNotify
{
    SubstitutePathNotify() {};
    
    const com::sun::star::uno::Sequence<rtl::OUString> aPropertyNames;
};

class SubstituteVariables : public ::std::hash_map< ::rtl::OUString,
                                                    SubstituteRule,
                                                    rtl::OUStringHash,
                                                    ::std::equal_to< ::rtl::OUString > >
{
    public:
        inline void free()
        {
            SubstituteVariables().swap( *this );
        }
};

typedef std::vector< SubstituteRule > SubstituteRuleVector;
class SubstitutePathVariables_Impl : public utl::ConfigItem
{
    public:
        SubstitutePathVariables_Impl( const Link& aNotifyLink );
        virtual ~SubstitutePathVariables_Impl();

        static OperatingSystem GetOperatingSystemFromString( const rtl::OUString& );
        static EnvironmentType GetEnvTypeFromString( const rtl::OUString& );

        void                   GetSharePointsRules( SubstituteVariables& aSubstVarMap );

        /** is called from the ConfigManager before application ends or from the
            PropertyChangeListener if the sub tree broadcasts changes. */
        virtual void Notify( const com::sun::star::uno::Sequence< rtl::OUString >& aPropertyNames );
        virtual void Commit();

        private:
            // Wrapper methods for low-level functions
            OperatingSystem         GetOperatingSystem();
            const rtl::OUString&    GetYPDomainName();
            const rtl::OUString&    GetDNSDomainName();
            const rtl::OUString&    GetNTDomainName();
            const rtl::OUString&    GetHostName();

            bool                    FilterRuleSet( const SubstituteRuleVector& aRuleSet, SubstituteRule& aActiveRule );

            void                    ReadSharePointsFromConfiguration( com::sun::star::uno::Sequence< rtl::OUString >& aSharePointsSeq );
            void                    ReadSharePointRuleSetFromConfiguration( const rtl::OUString& aSharePointName,
                                                                                                                                const rtl::OUString& aSharePointNodeName,
                                                                                                                                SubstituteRuleVector& aRuleSet );

            // Stored values for domains and host
            bool                    m_bYPDomainRetrieved;
            rtl::OUString           m_aYPDomain;
            bool                    m_bDNSDomainRetrieved;
            rtl::OUString           m_aDNSDomain;
            bool                    m_bNTDomainRetrieved;
            rtl::OUString           m_aNTDomain;
            bool                    m_bHostRetrieved;
            rtl::OUString           m_aHost;
            bool                    m_bOSRetrieved;
            OperatingSystem         m_eOSType;

            Link                    m_aListenerNotify;
            const rtl::OUString     m_aSharePointsNodeName;
            const rtl::OUString     m_aDirPropertyName;
            const rtl::OUString     m_aEnvPropertyName;
            const rtl::OUString     m_aLevelSep;
};

enum PreDefVariable
{
    PREDEFVAR_INST,
    PREDEFVAR_PROG,
    PREDEFVAR_USER,
    PREDEFVAR_WORK,
    PREDEFVAR_HOME,
    PREDEFVAR_TEMP,
    PREDEFVAR_PATH,
    PREDEFVAR_LANG,
    PREDEFVAR_LANGID,
    PREDEFVAR_VLANG,
    PREDEFVAR_INSTPATH,
    PREDEFVAR_PROGPATH,
    PREDEFVAR_USERPATH,
    PREDEFVAR_INSTURL,
    PREDEFVAR_PROGURL,
    PREDEFVAR_USERURL,
    PREDEFVAR_WORKDIRURL,
    // --> PB 2004-10-27 #i32656# - new variable of hierarchy service
    PREDEFVAR_BASEINSTURL,
    PREDEFVAR_USERDATAURL,
    // <--
    PREDEFVAR_BRANDBASEURL,
    PREDEFVAR_COUNT
};

struct PredefinedPathVariables
{
    // Predefined variables supported by substitute variables
    LanguageType    m_eLanguageType;                    // Lanuage type of Office
    rtl::OUString   m_FixedVar[ PREDEFVAR_COUNT ];      // Variable value access by PreDefVariable
    rtl::OUString   m_FixedVarNames[ PREDEFVAR_COUNT ]; // Variable name access by PreDefVariable
};

struct ReSubstFixedVarOrder
{
    sal_Int32       nVarValueLength;
    PreDefVariable  eVariable;

    bool operator< ( const ReSubstFixedVarOrder& aFixedVarOrder ) const
    {
        // Reverse operator< to have high to low ordering
        return ( nVarValueLength > aFixedVarOrder.nVarValueLength );
    }
};

struct ReSubstUserVarOrder
{
    sal_Int32       nVarValueLength;
    rtl::OUString   aVarName;

    bool operator< ( const ReSubstUserVarOrder& aUserVarOrder ) const
    {
        // Reverse operator< to have high to low ordering
        return ( nVarValueLength > aUserVarOrder.nVarValueLength );
    }
};

typedef std::list< ReSubstFixedVarOrder > ReSubstFixedVarOrderVector;
typedef std::list< ReSubstUserVarOrder > ReSubstUserVarOrderVector;

class SubstitutePathVariables : private ThreadHelpBase, // Struct for right initialization of mutex member! Must be first of baseclasses.
                                public ::cppu::WeakImplHelper2< ::com::sun::star::util::XStringSubstitution, css::lang::XServiceInfo >
{
    friend class SubstitutePathVariables_Impl;

    public:
        SubstitutePathVariables( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xServiceManager );
        virtual ~SubstitutePathVariables();

        //  XInterface, XTypeProvider, XServiceInfo
        DECLARE_XSERVICEINFO

        // XStringSubstitution
        virtual rtl::OUString SAL_CALL substituteVariables( const ::rtl::OUString& aText, sal_Bool bSubstRequired )
            throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException);
        virtual rtl::OUString SAL_CALL reSubstituteVariables( const ::rtl::OUString& aText )
            throw (::com::sun::star::uno::RuntimeException);
        virtual ::rtl::OUString SAL_CALL getSubstituteVariableValue( const ::rtl::OUString& variable )
            throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException);

        protected:
            DECL_LINK( implts_ConfigurationNotify, SubstitutePathNotify* );

            void            SetPredefinedPathVariables( PredefinedPathVariables& );
            rtl::OUString   ConvertOSLtoUCBURL( const rtl::OUString& aOSLCompliantURL ) const;

            // Special case (transient) values can change during runtime!
            // Don't store them in the pre defined struct
            rtl::OUString   GetWorkPath() const;
            rtl::OUString   GetWorkVariableValue() const;
            rtl::OUString   GetPathVariableValue() const;

            rtl::OUString   GetHomeVariableValue() const;

            // XStringSubstitution implementation methods
            rtl::OUString impl_substituteVariable( const ::rtl::OUString& aText, bool bSustRequired )
                throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException);
            rtl::OUString impl_reSubstituteVariables( const ::rtl::OUString& aText )
                throw (::com::sun::star::uno::RuntimeException);
            ::rtl::OUString impl_getSubstituteVariableValue( const ::rtl::OUString& variable )
                throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException);

        private:
            class VarNameToIndexMap : public std::hash_map< ::rtl::OUString,
                                                            PreDefVariable,
                                                            rtl::OUStringHash,
                                                            ::std::equal_to< ::rtl::OUString > >
            {
                inline void free()
                {
                    VarNameToIndexMap().swap( *this );
                }
            };

            // heavy used string
            const rtl::OUString          m_aVarStart;
            const rtl::OUString          m_aVarEnd;

            VarNameToIndexMap            m_aPreDefVarMap;         // Mapping from pre-def variable names to enum for array access
            SubstituteVariables          m_aSubstVarMap;          // Active rule set map indexed by variable name!
            PredefinedPathVariables      m_aPreDefVars;           // All predefined variables
            SubstitutePathVariables_Impl m_aImpl;                 // Implementation class that access the configuration
            ReSubstFixedVarOrderVector   m_aReSubstFixedVarOrder; // To speed up resubstitution fixed variables (order for lookup)
            ReSubstUserVarOrderVector    m_aReSubstUserVarOrder;  // To speed up resubstitution user variables
            com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > m_xServiceManager;
};

}

#endif // __FRAMEWORK_SERVICES_SUBSTPATHVARS_HXX_