<commit_before>/*************************************************************************
 *
 *  $RCSfile: datasourcemap.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: hr $ $Date: 2003-03-19 17:52:38 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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 for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef DBAUI_DATASOURCEMAP_HXX
#define DBAUI_DATASOURCEMAP_HXX

#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XNAMEACCESS_HPP_
#include <com/sun/star/container/XNameAccess.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COMPHELPER_STLTYPES_HXX_
#include <comphelper/stl_types.hxx>
#endif
#ifndef _STRING_HXX
#include <tools/string.hxx>
#endif

class SfxItemPool;
class SfxItemSet;
//.........................................................................
namespace dbaui
{
//.........................................................................

    //=====================================================================
    //= ODatasourceMap
    //=====================================================================
    class ODatasourceMap
    {
        struct DatasourceInfo
        {
            ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >
                                xDatasource;
            SfxItemSet*         pModifications;

            DatasourceInfo() :pModifications (NULL) {  }
            DatasourceInfo(const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxDS,
                    SfxItemSet* _pMods = NULL)
                :xDatasource(_rxDS), pModifications(_pMods) { }
        };

        ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >
                                m_xORB;                 /// service factory
        ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >
                                m_xDatabaseContext;     /// database context we're working in

        DECLARE_STL_USTRINGACCESS_MAP(DatasourceInfo, DatasourceInfos);
        DatasourceInfos         m_aDatasources;         /// known infos about data sources

        // deleted data sources, not necessarily with distinct names, that's why accessed via unique ids
        DECLARE_STL_MAP(sal_Int32, DatasourceInfo, ::std::less< sal_Int32 >, MapInt2Info);
        MapInt2Info             m_aDeletedDatasources;

    public:
        /// iterating through all data sources
        class Iterator;
        friend class ODatasourceMap::Iterator;

        /// encapsulates the infos about a data source for access from outside the class
        class ODatasourceInfo;
        friend class ODatasourceMap::ODatasourceInfo;

        ODatasourceInfo operator[](const ::rtl::OUString _rName);

        ODatasourceMap(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > _rxORB);

        // get the database context
        ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >
                    getContext() { return m_xDatabaseContext; }

        /// first element for iterating through the datasources
        Iterator    begin();
        /// last element for iterating through the datasources
        Iterator    end();

        /// first element for iterating through the deleted datasources
        Iterator    beginDeleted();
        /// last element for iterating through the deleted datasources
        Iterator    endDeleted();

        /// check if the object contains a valid datasource enumeration
        sal_Bool    isValid() const { return m_xDatabaseContext.is(); }
        /// check if a datasource with the given name exists
        sal_Bool    exists(const ::rtl::OUString& _rName) const;
        /// return the number of datasources available
        sal_Int32   size() const { return m_aDatasources.size(); }
        /// clear the map (non-deleted and deleted items)
        void        clear();
        /// clear the map (deleted items only)
        void        clearDeleted();

        /// clear the modification items for a datasource
        void        clearModifiedFlag(const ::rtl::OUString& _rName);

        /** tell the map that a data source is scheduled to be deleted.
            @return     id for accessing the deleted data source later. -1 if no free id existed or an error occured
        */
        sal_Int32   markDeleted(const ::rtl::OUString& _rName);

        /** restores a datasource which has previously been marked as deleted.

            @param      _nAccessId      the access id as got from <method>markDeleted</method>
            @param      _rName          contains, upon return, the name of the datasource the access key refers to
            @return     sal_True if the datasource was successfully restored, sal_False if it could not be restored
                        because of a naming conflict (e.g. because another data source now has the name of the
                        to-be-restored one).
            @see    renamed
            @see    markDeleted
        */
        sal_Bool    restoreDeleted(sal_Int32 _nAccessId, ::rtl::OUString& _rName);

        /// remove an element from the map
        void        deleted(const ::rtl::OUString& _rName);
            // (should be an erase(const Iterator&), but this is way to general ...

        /// update the infos for a data source with a given item set
        void        update(const ::rtl::OUString& _rName, SfxItemSet& _rSet);
        /** Tells the map that an entry has been renamed in a sense that it should be accessible under
            a new name. This does not necesssarily mean that the data source has been renamed within
            it's database context
        */
        void        renamed(const ::rtl::OUString& _rOldName, const ::rtl::OUString& _rNewName);

        /** adjust the registration name if necessary

            The real name of the data source (as indicated in the SfxItemSet for this ds) may be another
            one than the name the ds is registered for. This method corrects this, the ds will become registered
            under it's real name.
            @param      _rName      the name the ds is registered for
            @return                 the real name of the data source
        */
        ::rtl::OUString adjustRealName(const ::rtl::OUString& _rName);

        /** create a new (floating) datasource

            The ds is inserted it into the map under the given name and returned.

            If no object could be created, nothing is inserted into the map.

            The item pool and the item ranges are used to create the initial SfxItemSet for the new ds.
        */
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >
                    createNew(const ::rtl::OUString& _rName, SfxItemPool* _pPool, const sal_uInt16* _pRanges);
    protected:
        /** ensure that the DatabaseInfo for the named object is filled

            This method allows us lazy access to the data sources: They're retrieved from the context
            only if they're accessed by somebody.
        */
        void    ensureObject(const ::rtl::OUString& _rName);
    };

    //-------------------------------------------------------------------------
    //- ODatasourceMap::ODatasourceInfo
    //-------------------------------------------------------------------------
    class ODatasourceMap::ODatasourceInfo
    {
        friend class ODatasourceMap;
        friend class ODatasourceMap::Iterator;

    private:
        ODatasourceMap*                             m_pOwner;
        const ODatasourceMap::DatasourceInfo&       m_rInfoImpl;
        ::rtl::OUString                             m_sName;
        sal_Int32                                   m_nAccessKey;

    public:
        ODatasourceInfo(const ODatasourceInfo& _rSource)
            :m_pOwner(_rSource.m_pOwner), m_sName(_rSource.m_sName), m_rInfoImpl(_rSource.m_rInfoImpl), m_nAccessKey(_rSource.m_nAccessKey) { }

        /// check if the datasource settings are modified
        sal_Bool        isModified() const;
        /// check if the datasource is to be created
        sal_Bool        isNew() const;
        /// get the name the datasource is registered under
        ::rtl::OUString getName() const { return m_sName; }
        /// get the original name of a datasource (may habe been renamed)
        ::rtl::OUString getOriginalName() const;
        /// get the real name of the datasource, which is the name which is in the item set
        ::rtl::OUString getRealName() const;
        /// check if the datasource should is about to be renamed (which means the original name does not equal the real name
        sal_Bool        isRenamed() const { return !isNew() && !getRealName().equals(getOriginalName()); }
        /// get the key used to acces the object in the data source map
        sal_Int32       getAccessKey() const { return m_nAccessKey; }

        /// return the datasource the object represents
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >
                        getDatasource() const;
        /** return the modifications for the data source

            The return value is non-NULL if and only if <method>isModified</method> returned sal_True
        */
        const SfxItemSet*
                        getModifications() const { return m_rInfoImpl.pModifications; }

        operator ::rtl::OUString() const { return getName(); }
        operator String() const { return getName().getStr(); }

        const ODatasourceInfo* const operator->() const { return this; }

    protected:
        ODatasourceInfo(
                ODatasourceMap* _pOwner, const ::rtl::OUString& _rName,
                const ODatasourceMap::DatasourceInfo& _rSource, sal_Int32 _nAccessKey)
            :m_pOwner(_pOwner), m_sName(_rName), m_rInfoImpl(_rSource), m_nAccessKey(_nAccessKey) { }
    };

    //-------------------------------------------------------------------------
    //- ODatasourceMap::Iterator
    //-------------------------------------------------------------------------
    class ODatasourceMap::Iterator
    {
        friend class ODatasourceMap;
    protected:
        ODatasourceMap*                                 m_pOwner;
        ODatasourceMap::ConstDatasourceInfosIterator    m_aPos;
        ODatasourceMap::ConstMapInt2InfoIterator        m_aPosDeleted;
        sal_Bool                                        m_bLoopingDeleted;

    public:
        Iterator(const Iterator& _rSource);

        ODatasourceInfo operator->() const;
        ODatasourceInfo operator*() const;

        /// prefix increment
        const Iterator& operator++();
        /// postfix increment
        const Iterator  operator++(int) { Iterator hold(*this); ++*this; return hold; }

        /// prefix decrement
        const Iterator& operator--();
        /// postfix decrement
        const Iterator  operator--(int) { Iterator hold(*this); --*this; return hold; }

    // compare two iterators
        friend bool operator==(const Iterator& lhs, const Iterator& rhs)
        {
            if (lhs.m_bLoopingDeleted)
                return lhs.m_aPosDeleted == rhs.m_aPosDeleted;
            else
                return lhs.m_aPos == rhs.m_aPos;
        }

        friend bool operator!=(const Iterator& lhs, const Iterator& rhs) { return !(lhs == rhs); }

    protected:
        Iterator(ODatasourceMap* _pOwner, ODatasourceMap::ConstDatasourceInfosIterator _rPos);
        Iterator(ODatasourceMap* _pOwner, ODatasourceMap::ConstMapInt2InfoIterator _rPos);

    protected:
        ::rtl::OUString implGetName(const ODatasourceMap::DatasourceInfo& _rInfo) const;
    };

//.........................................................................
}   // namespace dbaui
//.........................................................................

#endif DBAUI_DATASOURCEMAP_HXX

<commit_msg>INTEGRATION: CWS rt02 (1.2.98); FILE MERGED 2003/10/01 12:45:42 rt 1.2.98.1: #i19697# Fixed compiler warnings<commit_after>/*************************************************************************
 *
 *  $RCSfile: datasourcemap.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2003-10-06 15:03:04 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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 for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef DBAUI_DATASOURCEMAP_HXX
#define DBAUI_DATASOURCEMAP_HXX

#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XNAMEACCESS_HPP_
#include <com/sun/star/container/XNameAccess.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COMPHELPER_STLTYPES_HXX_
#include <comphelper/stl_types.hxx>
#endif
#ifndef _STRING_HXX
#include <tools/string.hxx>
#endif

class SfxItemPool;
class SfxItemSet;
//.........................................................................
namespace dbaui
{
//.........................................................................

    //=====================================================================
    //= ODatasourceMap
    //=====================================================================
    class ODatasourceMap
    {
        struct DatasourceInfo
        {
            ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >
                                xDatasource;
            SfxItemSet*         pModifications;

            DatasourceInfo() :pModifications (NULL) {  }
            DatasourceInfo(const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& _rxDS,
                    SfxItemSet* _pMods = NULL)
                :xDatasource(_rxDS), pModifications(_pMods) { }
        };

        ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >
                                m_xORB;                 /// service factory
        ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >
                                m_xDatabaseContext;     /// database context we're working in

        DECLARE_STL_USTRINGACCESS_MAP(DatasourceInfo, DatasourceInfos);
        DatasourceInfos         m_aDatasources;         /// known infos about data sources

        // deleted data sources, not necessarily with distinct names, that's why accessed via unique ids
        DECLARE_STL_MAP(sal_Int32, DatasourceInfo, ::std::less< sal_Int32 >, MapInt2Info);
        MapInt2Info             m_aDeletedDatasources;

    public:
        /// iterating through all data sources
        class Iterator;
        friend class ODatasourceMap::Iterator;

        /// encapsulates the infos about a data source for access from outside the class
        class ODatasourceInfo;
        friend class ODatasourceMap::ODatasourceInfo;

        ODatasourceInfo operator[](const ::rtl::OUString _rName);

        ODatasourceMap(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > _rxORB);

        // get the database context
        ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess >
                    getContext() { return m_xDatabaseContext; }

        /// first element for iterating through the datasources
        Iterator    begin();
        /// last element for iterating through the datasources
        Iterator    end();

        /// first element for iterating through the deleted datasources
        Iterator    beginDeleted();
        /// last element for iterating through the deleted datasources
        Iterator    endDeleted();

        /// check if the object contains a valid datasource enumeration
        sal_Bool    isValid() const { return m_xDatabaseContext.is(); }
        /// check if a datasource with the given name exists
        sal_Bool    exists(const ::rtl::OUString& _rName) const;
        /// return the number of datasources available
        sal_Int32   size() const { return m_aDatasources.size(); }
        /// clear the map (non-deleted and deleted items)
        void        clear();
        /// clear the map (deleted items only)
        void        clearDeleted();

        /// clear the modification items for a datasource
        void        clearModifiedFlag(const ::rtl::OUString& _rName);

        /** tell the map that a data source is scheduled to be deleted.
            @return     id for accessing the deleted data source later. -1 if no free id existed or an error occured
        */
        sal_Int32   markDeleted(const ::rtl::OUString& _rName);

        /** restores a datasource which has previously been marked as deleted.

            @param      _nAccessId      the access id as got from <method>markDeleted</method>
            @param      _rName          contains, upon return, the name of the datasource the access key refers to
            @return     sal_True if the datasource was successfully restored, sal_False if it could not be restored
                        because of a naming conflict (e.g. because another data source now has the name of the
                        to-be-restored one).
            @see    renamed
            @see    markDeleted
        */
        sal_Bool    restoreDeleted(sal_Int32 _nAccessId, ::rtl::OUString& _rName);

        /// remove an element from the map
        void        deleted(const ::rtl::OUString& _rName);
            // (should be an erase(const Iterator&), but this is way to general ...

        /// update the infos for a data source with a given item set
        void        update(const ::rtl::OUString& _rName, SfxItemSet& _rSet);
        /** Tells the map that an entry has been renamed in a sense that it should be accessible under
            a new name. This does not necesssarily mean that the data source has been renamed within
            it's database context
        */
        void        renamed(const ::rtl::OUString& _rOldName, const ::rtl::OUString& _rNewName);

        /** adjust the registration name if necessary

            The real name of the data source (as indicated in the SfxItemSet for this ds) may be another
            one than the name the ds is registered for. This method corrects this, the ds will become registered
            under it's real name.
            @param      _rName      the name the ds is registered for
            @return                 the real name of the data source
        */
        ::rtl::OUString adjustRealName(const ::rtl::OUString& _rName);

        /** create a new (floating) datasource

            The ds is inserted it into the map under the given name and returned.

            If no object could be created, nothing is inserted into the map.

            The item pool and the item ranges are used to create the initial SfxItemSet for the new ds.
        */
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >
                    createNew(const ::rtl::OUString& _rName, SfxItemPool* _pPool, const sal_uInt16* _pRanges);
    protected:
        /** ensure that the DatabaseInfo for the named object is filled

            This method allows us lazy access to the data sources: They're retrieved from the context
            only if they're accessed by somebody.
        */
        void    ensureObject(const ::rtl::OUString& _rName);
    };

    //-------------------------------------------------------------------------
    //- ODatasourceMap::ODatasourceInfo
    //-------------------------------------------------------------------------
    class ODatasourceMap::ODatasourceInfo
    {
        friend class ODatasourceMap;
        friend class ODatasourceMap::Iterator;

    private:
        ODatasourceMap*                             m_pOwner;
        const ODatasourceMap::DatasourceInfo&       m_rInfoImpl;
        ::rtl::OUString                             m_sName;
        sal_Int32                                   m_nAccessKey;

    public:
        ODatasourceInfo(const ODatasourceInfo& _rSource)
            :m_pOwner(_rSource.m_pOwner), m_sName(_rSource.m_sName), m_rInfoImpl(_rSource.m_rInfoImpl), m_nAccessKey(_rSource.m_nAccessKey) { }

        /// check if the datasource settings are modified
        sal_Bool        isModified() const;
        /// check if the datasource is to be created
        sal_Bool        isNew() const;
        /// get the name the datasource is registered under
        ::rtl::OUString getName() const { return m_sName; }
        /// get the original name of a datasource (may habe been renamed)
        ::rtl::OUString getOriginalName() const;
        /// get the real name of the datasource, which is the name which is in the item set
        ::rtl::OUString getRealName() const;
        /// check if the datasource should is about to be renamed (which means the original name does not equal the real name
        sal_Bool        isRenamed() const { return !isNew() && !getRealName().equals(getOriginalName()); }
        /// get the key used to acces the object in the data source map
        sal_Int32       getAccessKey() const { return m_nAccessKey; }

        /// return the datasource the object represents
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >
                        getDatasource() const;
        /** return the modifications for the data source

            The return value is non-NULL if and only if <method>isModified</method> returned sal_True
        */
        const SfxItemSet*
                        getModifications() const { return m_rInfoImpl.pModifications; }

        operator ::rtl::OUString() const { return getName(); }
        operator String() const { return getName().getStr(); }

        const ODatasourceInfo* const operator->() const { return this; }

    protected:
        ODatasourceInfo(
                ODatasourceMap* _pOwner, const ::rtl::OUString& _rName,
                const ODatasourceMap::DatasourceInfo& _rSource, sal_Int32 _nAccessKey)
            :m_pOwner(_pOwner), m_sName(_rName), m_rInfoImpl(_rSource), m_nAccessKey(_nAccessKey) { }
    };

    //-------------------------------------------------------------------------
    //- ODatasourceMap::Iterator
    //-------------------------------------------------------------------------
    class ODatasourceMap::Iterator
    {
        friend class ODatasourceMap;
    protected:
        ODatasourceMap*                                 m_pOwner;
        ODatasourceMap::ConstDatasourceInfosIterator    m_aPos;
        ODatasourceMap::ConstMapInt2InfoIterator        m_aPosDeleted;
        sal_Bool                                        m_bLoopingDeleted;

    public:
        Iterator(const Iterator& _rSource);

        ODatasourceInfo operator->() const;
        ODatasourceInfo operator*() const;

        /// prefix increment
        const Iterator& operator++();
        /// postfix increment
        const Iterator  operator++(int) { Iterator hold(*this); ++*this; return hold; }

        /// prefix decrement
        const Iterator& operator--();
        /// postfix decrement
        const Iterator  operator--(int) { Iterator hold(*this); --*this; return hold; }

    // compare two iterators
        friend bool operator==(const Iterator& lhs, const Iterator& rhs)
        {
            if (lhs.m_bLoopingDeleted)
                return lhs.m_aPosDeleted == rhs.m_aPosDeleted;
            else
                return lhs.m_aPos == rhs.m_aPos;
        }

        friend bool operator!=(const Iterator& lhs, const Iterator& rhs) { return !(lhs == rhs); }

    protected:
        Iterator(ODatasourceMap* _pOwner, ODatasourceMap::ConstDatasourceInfosIterator _rPos);
        Iterator(ODatasourceMap* _pOwner, ODatasourceMap::ConstMapInt2InfoIterator _rPos);

    protected:
        ::rtl::OUString implGetName(const ODatasourceMap::DatasourceInfo& _rInfo) const;
    };

//.........................................................................
}   // namespace dbaui
//.........................................................................

#endif // DBAUI_DATASOURCEMAP_HXX

<|endoftext|>


<commit_before>#include <iostream>

#include "player.h"
#include "Hand.h"

const char* Player::VERSION = "Pwnies";

int minimum_raise;
int in_action;
int our_bet;
int current_buy_in;
Hand2 hole_cards;

int toAction(HoleCardRank rank) {
    std::cerr << "XXXXXXXXX action is " << int(rank) << std::endl;

    switch (rank) {
        case HoleCardRank::ALLIN:
            return 5000;
        case HoleCardRank::RAISABLE:
            return current_buy_in - our_bet + 3*minimum_raise;
        default:
            std::cerr << "Unknown action" << std::endl;
            return 0;
        case HoleCardRank::FOLDABLE:
            return 0;
        case HoleCardRank::CALLABLE:
            if (current_buy_in - our_bet < 100) {
                return current_buy_in - our_bet;
            } else {
                return 0;
            }
    }
}

int preFlop(json::Value game_state) {
    return toAction(rankHoleCard(hole_cards));
}

int handlePair(json::Value game_state) {
    auto board = parseHandN(game_state["community_cards"]);
    if (game_state["eval"]["value"].ToInt() == board.back().rank && (
        board.back().rank == hole_cards[0].rank ||
        board.back().rank == hole_cards[1].rank))
    {
        // we have the highest pair
        return toAction(HoleCardRank::RAISABLE);
    }
    if (hole_cards[0].rank == hole_cards[1].rank &&
        board.back().rank >= hole_cards[1].rank)
    {
        return toAction(HoleCardRank::ALLIN);
    }
    return toAction(HoleCardRank::CALLABLE); // pair
}

int flop(json::Value game_state) {
    if (!game_state.HasKey("eval")) {
        std::cerr << "NO eval in flop()" << std::endl;
        return preFlop(game_state);
    }

    int rank = game_state["eval"]["rank"].ToInt();

    switch (rank) {
        default:
            std::cerr << "Unknown rank" << std::endl;
        case 0: return toAction(HoleCardRank::FOLDABLE);
        case 1: return handlePair(game_state);
        case 2: return toAction(HoleCardRank::CALLABLE);
        case 3: return toAction(HoleCardRank::RAISABLE);
        case 4: return toAction(HoleCardRank::RAISABLE);
        case 5: return toAction(HoleCardRank::ALLIN);
        case 6: return toAction(HoleCardRank::ALLIN);
        case 7: return toAction(HoleCardRank::ALLIN);
        case 8: return toAction(HoleCardRank::ALLIN);
    }
}

int turn(json::Value game_state) {
    if (!game_state.HasKey("eval")) {
        std::cerr << "NO eval in turn()" << std::endl;
        return preFlop(game_state);
    }
    return flop(game_state);
}

int river(json::Value game_state) {
    if (!game_state.HasKey("eval")) {
        std::cerr << "NO eval in river()" << std::endl;
        return preFlop(game_state);
    }
    return flop(game_state);
}

int Player::betRequest(json::Value game_state) {
    minimum_raise = game_state["minimum_raise"].ToInt();
    in_action = game_state["in_action"].ToInt();
    our_bet = game_state["players"][in_action]["bet"];
    current_buy_in = game_state["current_buy_in"];

    hole_cards = parseHand2(game_state["players"][in_action]["hole_cards"]);

    std::cerr << "XXXXXXXXXX Our hand is = " << hole_cards << std::endl;

    switch (game_state["community_cards"].ToArray().size()) {
        default:
        case 0:
            return preFlop(game_state);
        case 3:
            return flop(game_state);
        case 4:
            return turn(game_state);
        case 5:
            return river(game_state);
    }

}

void Player::showdown(json::Value game_state)
{
}
<commit_msg>Make things independent of the pot size<commit_after>#include <iostream>

#include "player.h"
#include "Hand.h"

const char* Player::VERSION = "Pwnies";

int minimum_raise;
int in_action;
int our_bet;
int current_buy_in;
int pot;
Hand2 hole_cards;

int toAction(HoleCardRank rank) {
    std::cerr << "XXXXXXXXX action is " << int(rank) << std::endl;

    switch (rank) {
        case HoleCardRank::ALLIN:
            return 5000;
        case HoleCardRank::RAISABLE:
            return current_buy_in - our_bet + 3*minimum_raise;
        default:
            std::cerr << "Unknown action" << std::endl;
            return 0;
        case HoleCardRank::FOLDABLE:
            return 0;
        case HoleCardRank::CALLABLE:
            {
                int to_call = current_buy_in - our_bet;
                int pot_sum = pot + to_call;
                if (pot_sum > 0 && double(to_call) / pot_sum < 0.2) {
                    return current_buy_in - our_bet;
                } else {
                    return 0;
                }
            }
    }
}

int preFlop(json::Value game_state) {
    return toAction(rankHoleCard(hole_cards));
}

int handlePair(json::Value game_state) {
    auto board = parseHandN(game_state["community_cards"]);
    if (game_state["eval"]["value"].ToInt() == board.back().rank && (
        board.back().rank == hole_cards[0].rank ||
        board.back().rank == hole_cards[1].rank))
    {
        // we have the highest pair
        return toAction(HoleCardRank::RAISABLE);
    }
    if (hole_cards[0].rank == hole_cards[1].rank &&
        board.back().rank >= hole_cards[1].rank)
    {
        return toAction(HoleCardRank::ALLIN);
    }
    return toAction(HoleCardRank::CALLABLE); // pair
}

int flop(json::Value game_state) {
    if (!game_state.HasKey("eval")) {
        std::cerr << "NO eval in flop()" << std::endl;
        return preFlop(game_state);
    }

    int rank = game_state["eval"]["rank"].ToInt();

    switch (rank) {
        default:
            std::cerr << "Unknown rank" << std::endl;
        case 0: return toAction(HoleCardRank::FOLDABLE);
        case 1: return handlePair(game_state);
        case 2: return toAction(HoleCardRank::CALLABLE);
        case 3: return toAction(HoleCardRank::RAISABLE);
        case 4: return toAction(HoleCardRank::RAISABLE);
        case 5: return toAction(HoleCardRank::ALLIN);
        case 6: return toAction(HoleCardRank::ALLIN);
        case 7: return toAction(HoleCardRank::ALLIN);
        case 8: return toAction(HoleCardRank::ALLIN);
    }
}

int turn(json::Value game_state) {
    if (!game_state.HasKey("eval")) {
        std::cerr << "NO eval in turn()" << std::endl;
        return preFlop(game_state);
    }
    return flop(game_state);
}

int river(json::Value game_state) {
    if (!game_state.HasKey("eval")) {
        std::cerr << "NO eval in river()" << std::endl;
        return preFlop(game_state);
    }
    return flop(game_state);
}

int Player::betRequest(json::Value game_state) {
    minimum_raise = game_state["minimum_raise"].ToInt();
    in_action = game_state["in_action"].ToInt();
    our_bet = game_state["players"][in_action]["bet"];
    current_buy_in = game_state["current_buy_in"];
    pot = game_state["pot"];

    hole_cards = parseHand2(game_state["players"][in_action]["hole_cards"]);

    std::cerr << "XXXXXXXXXX Our hand is = " << hole_cards << std::endl;

    switch (game_state["community_cards"].ToArray().size()) {
        default:
        case 0:
            return preFlop(game_state);
        case 3:
            return flop(game_state);
        case 4:
            return turn(game_state);
        case 5:
            return river(game_state);
    }

}

void Player::showdown(json::Value game_state)
{
}
<|endoftext|>


<commit_before>/*
 *   Copyright (c) 2014 Kulykov Oleh <nonamedemail@gmail.com>
 *
 *   Permission is hereby granted, free of charge, to any person obtaining a copy
 *   of this software and associated documentation files (the "Software"), to deal
 *   in the Software without restriction, including without limitation the rights
 *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *   copies of the Software, and to permit persons to whom the Software is
 *   furnished to do so, subject to the following conditions:
 *
 *   The above copyright notice and this permission notice shall be included in
 *   all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *   THE SOFTWARE.
 */

#include "REThread.h"
#include "REMutex.h"

#ifdef __RE_DEBUG_MODE__
#include "../../include/recore/RELog.h"
#endif

#if defined(HAVE_RECORE_SDK_CONFIG_H)
#include "recore_sdk_config.h"
#endif

#if defined(HAVE_FAYECPP_CONFIG_H)
#include "fayecpp_config.h"
#endif

#if defined(HAVE_PTHREAD_H)
#include <pthread.h>
#elif defined(__RE_OS_WINDOWS__)
/* Use Windows threading */
#ifndef __RE_USING_WINDOWS_THREADS__
#define __RE_USING_WINDOWS_THREADS__ 1
#endif
#include <Windows.h>
#endif /* __RE_OS_WINDOWS__ */

#if defined(HAVE_SYS_TIME_H)
#include <sys/time.h>
#endif

#if defined(HAVE_STRING_H)
#include <string.h>
#endif

#if defined(HAVE_ERRNO_H)
#include <errno.h>
#endif

#if defined(HAVE_SYS_ERRNO_H)
#include <sys/errno.h>
#endif

#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif

#if defined(HAVE_DISPATCH_DISPATCH_H)
#include <dispatch/dispatch.h>
#endif

#if defined(HAVE_SIGNAL_H)
#include <signal.h>
#endif

#if !defined(HAVE_FUNCTION_PTHREAD_CANCEL) && defined(HAVE_SIGNAL_H)
#include <signal.h>
#endif

#undef HAVE_FUNCTION_PTHREAD_CANCEL

namespace FayeCpp {

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

class REThreadInternal
{
private:
	REThread * _parent;

#if defined(HAVE_PTHREAD_H)
	pthread_t _thread;
	pthread_attr_t _attr;
#elif defined(__RE_USING_WINDOWS_THREADS__)
	HANDLE _thread;
#endif

public:
	bool start();
	bool cancel();

	REThreadInternal(REThread * parent);
	~REThreadInternal();

#if defined(HAVE_PTHREAD_H)
	static void * threadFunction(void * p);
	static pthread_t mainPThread;

#elif defined(__RE_USING_WINDOWS_THREADS__)
	static DWORD mainThreadID;
	static DWORD WINAPI threadProc(LPVOID lpParameter);
#endif
};

#if defined(HAVE_PTHREAD_H)
pthread_t REThreadInternal::mainPThread = (pthread_t)0;
void * REThreadInternal::threadFunction(void * p)
{
	REThreadInternal * ti = static_cast<REThreadInternal *>(p);
	REThread * t = ti->_parent;

	if (t)
	{
		t->threadBody();
	}

	return p;
}
#elif defined(__RE_USING_WINDOWS_THREADS__)
DWORD REThreadInternal::mainThreadID = 0;
DWORD REThreadInternal::threadProc(LPVOID lpParameter)
{
	REThreadInternal * ti = static_cast<REThreadInternal *>(lpParameter);
	REThread * t = ti->_parent;

	if (t)
	{
		t->threadBody();
	}

	return 0;
}
#endif

bool REThreadInternal::cancel()
{
#if defined(HAVE_PTHREAD_H)
	int s = 0;

#if defined(HAVE_FUNCTION_PTHREAD_CANCEL)
	s = pthread_cancel(_thread);
	if (s != 0)
	{
		return false;
	}
#else
	s = pthread_kill(_thread, SIGUSR2);
	if (s != 0)
	{
		RELog::log("REThread: no function 'pthread_cancel' && error 'pthread_kill' thread %lu, error = %i",
				   (unsigned long)_thread,
				   s);
	}
#endif

	if (!_parent->isJoinable())
	{
		return true;
	}

	void * r = NULL;
	s = pthread_join(_thread, &r);
	if (s != 0)
	{

#if defined(HAVE_ERRNO_H) || defined(HAVE_SYS_ERRNO_H)
		switch (s)
		{
			case EDEADLK:
				printf("\nREThread: A deadlock was detected (e.g., two threads tried to join with each other); or thread specifies the calling thread.");
			break;

			case EINVAL:
				printf("\nREThread: Thread is not a joinable thread. Another thread is already waiting to join with this thread.");
			break;

			case ESRCH:
				printf("\nREThread: No thread with the ID thread could be found.");
			break;

			default:
			break;
		}
#endif	/* HAVE_ERRNO_H || HAVE_SYS_ERRNO_H */
		return false;
	}

#if defined(HAVE_FUNCTION_PTHREAD_CANCEL)
	const bool res = (r == PTHREAD_CANCELED);
#else
	const bool res = true;
#endif
	return res;

#elif defined (__RE_USING_WINDOWS_THREADS__)
	if (_thread)
	{
		bool isAlive = false;
		DWORD dwExitCode = 0;
		if (GetExitCodeThread(_thread, &dwExitCode))
		{
			// if return code is STILL_ACTIVE,
			// then thread is live.
			isAlive = (dwExitCode == STILL_ACTIVE);
		}
		if (isAlive)
		{
			TerminateThread(_thread, 0);
		}
		CloseHandle(_thread);
		_thread = (HANDLE)0;
		return true;
	}
#endif

	return true;
}

bool REThreadInternal::start()
{
#if defined(HAVE_PTHREAD_H)
	return (pthread_create(&_thread, &_attr, REThreadInternal::threadFunction, (void *)this) == 0);
#elif defined(__RE_USING_WINDOWS_THREADS__)
	HANDLE hThread = CreateThread(NULL, 0, REThreadInternal::threadProc, (LPVOID)this, 0, NULL);
	if (hThread)
	{
		_thread = hThread;
		return true;
	}
#endif

	return false;
}

#if !defined(HAVE_FUNCTION_PTHREAD_CANCEL) && defined(HAVE_PTHREAD_H)
static void thread_exit_handler(int sig)
{
	pthread_exit(0);
}
#endif

REThreadInternal::REThreadInternal(REThread * parent) :
	_parent(parent)
{
#if defined(HAVE_PTHREAD_H)

#if !defined(HAVE_FUNCTION_PTHREAD_CANCEL)
	static bool needSetup = true;
	if (needSetup)
	{
		needSetup = false;
		struct sigaction actions;
		memset(&actions, 0, sizeof(actions));
		sigemptyset(&actions.sa_mask);
		actions.sa_flags = 0;
		actions.sa_handler = thread_exit_handler;
		sigaction(SIGUSR2, &actions, NULL);
	}
#endif

	memset(&_thread, 0, sizeof(pthread_t));
	memset(&_attr, 0, sizeof(pthread_attr_t));

	pthread_attr_init(&_attr);

#if defined(HAVE_FUNCTION_PTHREAD_ATTR_SETSCOPE)
	pthread_attr_setscope(&_attr, PTHREAD_SCOPE_SYSTEM);
#endif

	if (_parent->isJoinable())
	{
		pthread_attr_setdetachstate(&_attr, PTHREAD_CREATE_JOINABLE);
	}

	if (_parent->isDetached())
	{
		pthread_attr_setdetachstate(&_attr, PTHREAD_CREATE_DETACHED);
	}
#elif defined(__RE_USING_WINDOWS_THREADS__)
	_thread = (HANDLE)0;
#endif
}

REThreadInternal::~REThreadInternal()
{
#if defined(HAVE_PTHREAD_H)
	pthread_attr_destroy(&_attr);
#endif
}

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

/// Start thread's work
bool REThread::start()
{
	if (_t)
	{
		return false;
	}

	_t = new REThreadInternal(this);
	if (_t)
	{
		const bool r = _t->start();
		if (!r)
		{
			delete _t;
			_t = NULL;
		}
		return r;
	}

	return false;
}

/// Cancels thread
bool REThread::cancel()
{
	if (_t)
	{
		const bool r = _t->cancel();
		if (r)
		{
			delete _t;
			_t = NULL;
		}
		return r;
	}

	return true;
}

bool REThread::isJoinable() const
{
	return _isJoinable;
}

bool REThread::isDetached() const
{
	return _isDetached;
}

void REThread::setJoinable(bool isJoin)
{
#if defined(HAVE_PTHREAD_H)
	if (!_t)
	{
		//TODO: check if possible
		_isJoinable = isJoin;
		if (_isJoinable)
		{
			_isDetached = false;
		}
	}
#endif
}

void REThread::setDetached(bool isDetach)
{
#if defined(HAVE_PTHREAD_H)
	if (!_t)
	{
		//TODO: check if possible
		_isDetached = isDetach;
		if (_isDetached)
		{
			_isJoinable = false;
		}
	}
#endif
}

REThread::REThread() :
	_t(NULL),
	_isJoinable(false),
	_isDetached(false)
{
//	REThreadsPool::pool();

#if defined(HAVE_PTHREAD_H)
	this->setJoinable(true);
#endif

#if defined(HAVE_PTHREAD_H)
	if (REThreadInternal::mainPThread == (pthread_t)0)
	{
		REThreadInternal::mainPThread = pthread_self();
	}
#elif defined(__RE_USING_WINDOWS_THREADS__)
	if (REThreadInternal::mainThreadID == 0)
	{
		REThreadInternal::mainThreadID = GetCurrentThreadId();
	}
#endif
}

REThread::~REThread()
{
	this->cancel();
}

uintptr_t REThread::mainThreadIdentifier()
{
	uintptr_t thID = 0;
#if defined(HAVE_PTHREAD_H)
	if (REThreadInternal::mainPThread == (pthread_t)0)
	{
		REThreadInternal::mainPThread = pthread_self();
	}
	thID = ((uintptr_t)REThreadInternal::mainPThread);
#elif defined(__RE_USING_WINDOWS_THREADS__)
	if (REThreadInternal::mainThreadID == 0)
	{
		REThreadInternal::mainThreadID = GetCurrentThreadId();
	}
	thID = ((uintptr_t)REThreadInternal::mainThreadID);
#endif
	return thID;
}

uintptr_t REThread::currentThreadIdentifier()
{
	uintptr_t thID = 0;
#if defined(HAVE_PTHREAD_H)
	thID = ((uintptr_t)pthread_self());
#elif defined(__RE_USING_WINDOWS_THREADS__)
	thID = ((uintptr_t)GetCurrentThreadId());
#endif
	return thID;
}

#include <math.h>

uint64_t __convertSecondsToMicroseconds(const double seconds)
{
	double fullSeconds = 0.0;
	const double fractSecond = modf(seconds, &fullSeconds);
	const uint64_t fullIntMicrosec = (uint64_t)fullSeconds * 1000000;
	const uint64_t fractIntMicrosec = (uint64_t)fractSecond * 1000000;
	return (fullIntMicrosec + fractIntMicrosec);
}

void REThread::uSleep(const uint32_t microseconds)
{
#if defined(__RE_OS_WINDOWS__)
	LARGE_INTEGER time1, time2, sysFreq;

	QueryPerformanceCounter(&time1);
	QueryPerformanceFrequency(&sysFreq);
	do
	{
		QueryPerformanceCounter(&time2);
	}

	while((time2.QuadPart - time1.QuadPart) < microseconds);
#endif

#if defined(HAVE_FUNCTION_USLEEP)
	usleep(microseconds);
#endif
}

void REThread::uSleepInSeconds(const double seconds)
{
	REThread::uSleep((uint32_t)__convertSecondsToMicroseconds(seconds));
}

	bool REThread::isMainThread()
	{
#if defined(HAVE_PTHREAD_H)
		pthread_t curThread = pthread_self();
		if (REThreadInternal::mainPThread)
		{
			return (pthread_equal(curThread, REThreadInternal::mainPThread) != 0);
		}
		else
		{
			REThreadInternal::mainPThread = curThread;
		}
#elif defined(__RE_USING_WINDOWS_THREADS__)
		const DWORD curTHID = GetCurrentThreadId();
		if (REThreadInternal::mainThreadID)
		{
			return (REThreadInternal::mainThreadID == curTHID);
		}
		else
		{
			REThreadInternal::mainThreadID = curTHID;
		}
#endif
		return true;
	}

}

<commit_msg>Removed temp undefine<commit_after>/*
 *   Copyright (c) 2014 Kulykov Oleh <nonamedemail@gmail.com>
 *
 *   Permission is hereby granted, free of charge, to any person obtaining a copy
 *   of this software and associated documentation files (the "Software"), to deal
 *   in the Software without restriction, including without limitation the rights
 *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *   copies of the Software, and to permit persons to whom the Software is
 *   furnished to do so, subject to the following conditions:
 *
 *   The above copyright notice and this permission notice shall be included in
 *   all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *   THE SOFTWARE.
 */

#include "REThread.h"
#include "REMutex.h"

#ifdef __RE_DEBUG_MODE__
#include "../../include/recore/RELog.h"
#endif

#if defined(HAVE_RECORE_SDK_CONFIG_H)
#include "recore_sdk_config.h"
#endif

#if defined(HAVE_FAYECPP_CONFIG_H)
#include "fayecpp_config.h"
#endif

#if defined(HAVE_PTHREAD_H)
#include <pthread.h>
#elif defined(__RE_OS_WINDOWS__)
/* Use Windows threading */
#ifndef __RE_USING_WINDOWS_THREADS__
#define __RE_USING_WINDOWS_THREADS__ 1
#endif
#include <Windows.h>
#endif /* __RE_OS_WINDOWS__ */

#if defined(HAVE_SYS_TIME_H)
#include <sys/time.h>
#endif

#if defined(HAVE_STRING_H)
#include <string.h>
#endif

#if defined(HAVE_ERRNO_H)
#include <errno.h>
#endif

#if defined(HAVE_SYS_ERRNO_H)
#include <sys/errno.h>
#endif

#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif

#if defined(HAVE_DISPATCH_DISPATCH_H)
#include <dispatch/dispatch.h>
#endif

#if defined(HAVE_SIGNAL_H)
#include <signal.h>
#endif

#if !defined(HAVE_FUNCTION_PTHREAD_CANCEL) && defined(HAVE_SIGNAL_H)
#include <signal.h>
#endif

namespace FayeCpp {

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

class REThreadInternal
{
private:
	REThread * _parent;

#if defined(HAVE_PTHREAD_H)
	pthread_t _thread;
	pthread_attr_t _attr;
#elif defined(__RE_USING_WINDOWS_THREADS__)
	HANDLE _thread;
#endif

public:
	bool start();
	bool cancel();

	REThreadInternal(REThread * parent);
	~REThreadInternal();

#if defined(HAVE_PTHREAD_H)
	static void * threadFunction(void * p);
	static pthread_t mainPThread;

#elif defined(__RE_USING_WINDOWS_THREADS__)
	static DWORD mainThreadID;
	static DWORD WINAPI threadProc(LPVOID lpParameter);
#endif
};

#if defined(HAVE_PTHREAD_H)
pthread_t REThreadInternal::mainPThread = (pthread_t)0;
void * REThreadInternal::threadFunction(void * p)
{
	REThreadInternal * ti = static_cast<REThreadInternal *>(p);
	REThread * t = ti->_parent;

	if (t)
	{
		t->threadBody();
	}

	return p;
}
#elif defined(__RE_USING_WINDOWS_THREADS__)
DWORD REThreadInternal::mainThreadID = 0;
DWORD REThreadInternal::threadProc(LPVOID lpParameter)
{
	REThreadInternal * ti = static_cast<REThreadInternal *>(lpParameter);
	REThread * t = ti->_parent;

	if (t)
	{
		t->threadBody();
	}

	return 0;
}
#endif

bool REThreadInternal::cancel()
{
#if defined(HAVE_PTHREAD_H)
	int s = 0;

#if defined(HAVE_FUNCTION_PTHREAD_CANCEL)
	s = pthread_cancel(_thread);
	if (s != 0)
	{
		return false;
	}
#else
	s = pthread_kill(_thread, SIGUSR2);
	if (s != 0)
	{
		RELog::log("REThread: no function 'pthread_cancel' && error 'pthread_kill' thread %lu, error = %i",
				   (unsigned long)_thread,
				   s);
	}
#endif

	if (!_parent->isJoinable())
	{
		return true;
	}

	void * r = NULL;
	s = pthread_join(_thread, &r);
	if (s != 0)
	{

#if defined(HAVE_ERRNO_H) || defined(HAVE_SYS_ERRNO_H)
		switch (s)
		{
			case EDEADLK:
				printf("\nREThread: A deadlock was detected (e.g., two threads tried to join with each other); or thread specifies the calling thread.");
			break;

			case EINVAL:
				printf("\nREThread: Thread is not a joinable thread. Another thread is already waiting to join with this thread.");
			break;

			case ESRCH:
				printf("\nREThread: No thread with the ID thread could be found.");
			break;

			default:
			break;
		}
#endif	/* HAVE_ERRNO_H || HAVE_SYS_ERRNO_H */
		return false;
	}

#if defined(HAVE_FUNCTION_PTHREAD_CANCEL)
	const bool res = (r == PTHREAD_CANCELED);
#else
	const bool res = true;
#endif
	return res;

#elif defined (__RE_USING_WINDOWS_THREADS__)
	if (_thread)
	{
		bool isAlive = false;
		DWORD dwExitCode = 0;
		if (GetExitCodeThread(_thread, &dwExitCode))
		{
			// if return code is STILL_ACTIVE,
			// then thread is live.
			isAlive = (dwExitCode == STILL_ACTIVE);
		}
		if (isAlive)
		{
			TerminateThread(_thread, 0);
		}
		CloseHandle(_thread);
		_thread = (HANDLE)0;
		return true;
	}
#endif

	return true;
}

bool REThreadInternal::start()
{
#if defined(HAVE_PTHREAD_H)
	return (pthread_create(&_thread, &_attr, REThreadInternal::threadFunction, (void *)this) == 0);
#elif defined(__RE_USING_WINDOWS_THREADS__)
	HANDLE hThread = CreateThread(NULL, 0, REThreadInternal::threadProc, (LPVOID)this, 0, NULL);
	if (hThread)
	{
		_thread = hThread;
		return true;
	}
#endif

	return false;
}

#if !defined(HAVE_FUNCTION_PTHREAD_CANCEL) && defined(HAVE_PTHREAD_H)
static void thread_exit_handler(int sig)
{
	pthread_exit(0);
}
#endif

REThreadInternal::REThreadInternal(REThread * parent) :
	_parent(parent)
{
#if defined(HAVE_PTHREAD_H)

#if !defined(HAVE_FUNCTION_PTHREAD_CANCEL)
	static bool needSetup = true;
	if (needSetup)
	{
		needSetup = false;
		struct sigaction actions;
		memset(&actions, 0, sizeof(actions));
		sigemptyset(&actions.sa_mask);
		actions.sa_flags = 0;
		actions.sa_handler = thread_exit_handler;
		sigaction(SIGUSR2, &actions, NULL);
	}
#endif

	memset(&_thread, 0, sizeof(pthread_t));
	memset(&_attr, 0, sizeof(pthread_attr_t));

	pthread_attr_init(&_attr);

#if defined(HAVE_FUNCTION_PTHREAD_ATTR_SETSCOPE)
	pthread_attr_setscope(&_attr, PTHREAD_SCOPE_SYSTEM);
#endif

	if (_parent->isJoinable())
	{
		pthread_attr_setdetachstate(&_attr, PTHREAD_CREATE_JOINABLE);
	}

	if (_parent->isDetached())
	{
		pthread_attr_setdetachstate(&_attr, PTHREAD_CREATE_DETACHED);
	}
#elif defined(__RE_USING_WINDOWS_THREADS__)
	_thread = (HANDLE)0;
#endif
}

REThreadInternal::~REThreadInternal()
{
#if defined(HAVE_PTHREAD_H)
	pthread_attr_destroy(&_attr);
#endif
}

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

/// Start thread's work
bool REThread::start()
{
	if (_t)
	{
		return false;
	}

	_t = new REThreadInternal(this);
	if (_t)
	{
		const bool r = _t->start();
		if (!r)
		{
			delete _t;
			_t = NULL;
		}
		return r;
	}

	return false;
}

/// Cancels thread
bool REThread::cancel()
{
	if (_t)
	{
		const bool r = _t->cancel();
		if (r)
		{
			delete _t;
			_t = NULL;
		}
		return r;
	}

	return true;
}

bool REThread::isJoinable() const
{
	return _isJoinable;
}

bool REThread::isDetached() const
{
	return _isDetached;
}

void REThread::setJoinable(bool isJoin)
{
#if defined(HAVE_PTHREAD_H)
	if (!_t)
	{
		//TODO: check if possible
		_isJoinable = isJoin;
		if (_isJoinable)
		{
			_isDetached = false;
		}
	}
#endif
}

void REThread::setDetached(bool isDetach)
{
#if defined(HAVE_PTHREAD_H)
	if (!_t)
	{
		//TODO: check if possible
		_isDetached = isDetach;
		if (_isDetached)
		{
			_isJoinable = false;
		}
	}
#endif
}

REThread::REThread() :
	_t(NULL),
	_isJoinable(false),
	_isDetached(false)
{
//	REThreadsPool::pool();

#if defined(HAVE_PTHREAD_H)
	this->setJoinable(true);
#endif

#if defined(HAVE_PTHREAD_H)
	if (REThreadInternal::mainPThread == (pthread_t)0)
	{
		REThreadInternal::mainPThread = pthread_self();
	}
#elif defined(__RE_USING_WINDOWS_THREADS__)
	if (REThreadInternal::mainThreadID == 0)
	{
		REThreadInternal::mainThreadID = GetCurrentThreadId();
	}
#endif
}

REThread::~REThread()
{
	this->cancel();
}

uintptr_t REThread::mainThreadIdentifier()
{
	uintptr_t thID = 0;
#if defined(HAVE_PTHREAD_H)
	if (REThreadInternal::mainPThread == (pthread_t)0)
	{
		REThreadInternal::mainPThread = pthread_self();
	}
	thID = ((uintptr_t)REThreadInternal::mainPThread);
#elif defined(__RE_USING_WINDOWS_THREADS__)
	if (REThreadInternal::mainThreadID == 0)
	{
		REThreadInternal::mainThreadID = GetCurrentThreadId();
	}
	thID = ((uintptr_t)REThreadInternal::mainThreadID);
#endif
	return thID;
}

uintptr_t REThread::currentThreadIdentifier()
{
	uintptr_t thID = 0;
#if defined(HAVE_PTHREAD_H)
	thID = ((uintptr_t)pthread_self());
#elif defined(__RE_USING_WINDOWS_THREADS__)
	thID = ((uintptr_t)GetCurrentThreadId());
#endif
	return thID;
}

#include <math.h>

uint64_t __convertSecondsToMicroseconds(const double seconds)
{
	double fullSeconds = 0.0;
	const double fractSecond = modf(seconds, &fullSeconds);
	const uint64_t fullIntMicrosec = (uint64_t)fullSeconds * 1000000;
	const uint64_t fractIntMicrosec = (uint64_t)fractSecond * 1000000;
	return (fullIntMicrosec + fractIntMicrosec);
}

void REThread::uSleep(const uint32_t microseconds)
{
#if defined(__RE_OS_WINDOWS__)
	LARGE_INTEGER time1, time2, sysFreq;

	QueryPerformanceCounter(&time1);
	QueryPerformanceFrequency(&sysFreq);
	do
	{
		QueryPerformanceCounter(&time2);
	}

	while((time2.QuadPart - time1.QuadPart) < microseconds);
#endif

#if defined(HAVE_FUNCTION_USLEEP)
	usleep(microseconds);
#endif
}

void REThread::uSleepInSeconds(const double seconds)
{
	REThread::uSleep((uint32_t)__convertSecondsToMicroseconds(seconds));
}

	bool REThread::isMainThread()
	{
#if defined(HAVE_PTHREAD_H)
		pthread_t curThread = pthread_self();
		if (REThreadInternal::mainPThread)
		{
			return (pthread_equal(curThread, REThreadInternal::mainPThread) != 0);
		}
		else
		{
			REThreadInternal::mainPThread = curThread;
		}
#elif defined(__RE_USING_WINDOWS_THREADS__)
		const DWORD curTHID = GetCurrentThreadId();
		if (REThreadInternal::mainThreadID)
		{
			return (REThreadInternal::mainThreadID == curTHID);
		}
		else
		{
			REThreadInternal::mainThreadID = curTHID;
		}
#endif
		return true;
	}

}

<|endoftext|>


<commit_before>#include "bzfsAPI.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

class uselessmine : public bz_Plugin, bz_CustomSlashCommandHandler
{
	virtual const char* Name (){return "Useless Mine";}
	virtual void Init (const char* /*config*/);
	virtual void Event(bz_EventData *eventData);
	virtual bool SlashCommand (int playerID,bz_ApiString command,bz_ApiString message,bz_APIStringList* params);
	virtual void Cleanup ();
	virtual int CountMines();
	virtual void SetMine(int playerID,float pos1,float pos2,float pos3);
	virtual void RemoveMine(int id);
	virtual void RemoveAllMines(int playerID);
	public:
		double spawnsafetime; //This variable can be modified to reflect how much time players have before being hit by mines after spawning
		bool mine[255]; //Whether or not the mine has been set.
		signed int mineplayer[255]; //Which player set up the mine.
		float minepos[255][3]; //The position of a mine.
		signed int mineteam[255]; //The team the mine was set on.
		double safetytime[255]; //The safe time limit that players have when they spawn. To prevent instant deaths.
		bool minenotify[255]; //Tells the player they have useless.
};

BZ_PLUGIN(uselessmine);

void uselessmine::Init(const char* /*commandline*/)
{
	spawnsafetime=5.0; //Tells the plugin to allow 5 seconds of grace time before activating mines on a player.

	bz_debugMessage(1,"Useless Mine plugin loaded");
	bz_registerCustomSlashCommand("mine",this);
	Register(bz_eFlagGrabbedEvent);
	Register(bz_ePlayerPartEvent);
	Register(bz_ePlayerUpdateEvent);
	Register(bz_ePlayerDieEvent);
	Register(bz_ePlayerSpawnEvent);
	int i;
	for (i=0;i<255;i++) {
		mine[i]=0;
		mineplayer[i]=-1;
		minepos[i][0]=0;
		minepos[i][1]=0;
		minepos[i][2]=0;
		mineteam[i]=-1;
		minenotify[i]=0;
	}
}

int uselessmine::CountMines()
{
	int i,mines;
	mines=0;
	for (i=0;i<255;i++) {
		if (mine[i]) {mines++;}
	}
	return mines;
}

void uselessmine::Cleanup(void)
{
	Flush();
	bz_removeCustomSlashCommand("mine");
	bz_debugMessage(1,"Useless Mine plugin unloaded");
}

void uselessmine::SetMine(int playerID,float pos1,float pos2,float pos3)
{
	int i;
	for (i=0;i<255;i++) {
		if (!mine[i]) {break;}
	}
	mine[i]=1;
	mineplayer[i]=playerID;
	minepos[i][0]=pos1;
	minepos[i][1]=pos2;
	minepos[i][2]=pos3;
	bz_BasePlayerRecord *pr = bz_getPlayerByIndex(playerID);
	if (pr) {
		mineteam[i]=pr->team;
		bz_freePlayerRecord(pr);
	}
}

void uselessmine::RemoveMine(int id)
{
	mine[id]=0;
}

void uselessmine::RemoveAllMines(int playerID)
{
	int i;
	for (i=0;i<255;i++) {
		if (mine[i] && mineplayer[i]==playerID) {
			RemoveMine(i);
		}
	}
}

bool uselessmine::SlashCommand(int playerID,bz_ApiString command,bz_ApiString message,bz_APIStringList* params)
{
	if (!strcmp("mine",command.c_str())) {
		bz_BasePlayerRecord *pr = bz_getPlayerByIndex(playerID);
		if (pr) {
			if (pr->currentFlag=="USeless (+US)") {
				bz_removePlayerFlag(playerID);
				SetMine(playerID,pr->lastKnownState.pos[0],pr->lastKnownState.pos[1],pr->lastKnownState.pos[2]);
			}
			bz_freePlayerRecord(pr);
		}
		return 1;
	}
}

void uselessmine::Event(bz_EventData *eventData)
{
	int playerID = -1;
	switch (eventData->eventType) {
		case bz_eFlagGrabbedEvent: {
			playerID=((bz_FlagGrabbedEventData_V1*)eventData)->playerID;
			/*bz_BasePlayerRecord *pr = bz_getPlayerByIndex(playerID);
			//bz_debugMessage(0,bz_getName(((bz_FlagGrabbedEventData_V1*)eventData)->flagID).c_str());
			if (pr) {
			if (!strcmp(pr->currentFlag.c_str(),"US")) {
				bz_sendTextMessage(BZ_SERVER,playerID,"You grabbed a Useless flag! Type /mine at any time to set a useless mine!");
			}
			bz_freePlayerRecord(pr);
			}*/
			minenotify[playerID]=1;
		}break;
		case bz_ePlayerPartEvent: {
			playerID=((bz_PlayerJoinPartEventData_V1*)eventData)->playerID;
			RemoveAllMines(playerID);
		}break;
		case bz_ePlayerUpdateEvent: {
			int i;
			playerID=((bz_PlayerUpdateEventData_V1*)eventData)->playerID;
			bz_BasePlayerRecord *pr = bz_getPlayerByIndex(playerID);
			if (pr) {
			if (minenotify[playerID] && pr->currentFlag=="USeless (+US)") {bz_sendTextMessage(BZ_SERVER,playerID,"You grabbed a Useless flag! Type /mine at any time to set a useless mine!");
			minenotify[playerID]=0;}
			for (i=0;i<255;i++) {
					if (mine[i] && mineplayer[i]!=playerID && (pr->team==eRogueTeam || pr->team!=mineteam[i])) {
						if (pr->lastKnownState.pos[0]>minepos[i][0]-((bz_getBZDBDouble("_shockOutRadius")*0.75))
						&& pr->lastKnownState.pos[0]<minepos[i][0]+((bz_getBZDBDouble("_shockOutRadius")*0.75))
						&& pr->lastKnownState.pos[1]>minepos[i][1]-((bz_getBZDBDouble("_shockOutRadius")*0.75))
						&& pr->lastKnownState.pos[1]<minepos[i][1]+((bz_getBZDBDouble("_shockOutRadius")*0.75))
						&& pr->lastKnownState.pos[2]>minepos[i][2]-((bz_getBZDBDouble("_shockOutRadius")*0.75))
						&& pr->lastKnownState.pos[2]<minepos[i][2]+((bz_getBZDBDouble("_shockOutRadius")*0.75))
						&& safetytime[playerID]<=bz_getCurrentTime()
						) {
							bz_fireWorldWep("SW",2.0,BZ_SERVER,minepos[i],0,0,i+1000,0);
							RemoveMine(i);
						}
					}
			}
			bz_freePlayerRecord(pr);
			}
		}break;
		case bz_ePlayerDieEvent:{
			playerID=((bz_PlayerDieEventData_V1*)eventData)->playerID;
			int i;
			for (i=0;i<255;i++) {
				if (((bz_PlayerDieEventData_V1*)eventData)->shotID==i+1000) {
					((bz_PlayerDieEventData_V1*)eventData)->killerID=mineplayer[i];
					bz_BasePlayerRecord *pr = bz_getPlayerByIndex(playerID);
					bz_BasePlayerRecord *kr = bz_getPlayerByIndex(mineplayer[i]);
					if (pr || kr) {
						if (pr && kr) {
						switch (rand() % 20) {
							case 0:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"%s was killed by %s's mine. [%d]",pr->callsign.c_str(),kr->callsign.c_str(),CountMines());
							}break;
							case 1:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"%s was owned by %s's mine. [%d]",pr->callsign.c_str(),kr->callsign.c_str(),CountMines());
							}break;
							case 2:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"%s was obliterated by %s's mine. [%d]",pr->callsign.c_str(),kr->callsign.c_str(),CountMines());
							}break;
							case 3:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"%s's tank disintegrated from %s's mine. [%d]",pr->callsign.c_str(),kr->callsign.c_str(),CountMines());
							}break;
							case 4:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"%s was permanently blinded by the bright light from %s's mine. [%d]",pr->callsign.c_str(),kr->callsign.c_str(),CountMines());
							}break;
							case 5:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"%s was sent shooting into the stars by %s's mine. [%d]",pr->callsign.c_str(),kr->callsign.c_str(),CountMines());
							}break;
							case 6:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"%s was never heard from again thanks to %s's mine. [%d]",pr->callsign.c_str(),kr->callsign.c_str(),CountMines());
							}break;
							case 7:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"We salute %s for taking an atrocious hit from %s's mine. [%d]",pr->callsign.c_str(),kr->callsign.c_str(),CountMines());
							}break;
							case 8:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"%s's mine left %s's tank parts scattered all over. [%d]",kr->callsign.c_str(),pr->callsign.c_str(),CountMines());
							}break;
							case 9:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"%s thought %s's mine was a shiny brand new car. [%d]",pr->callsign.c_str(),kr->callsign.c_str(),CountMines());
							}break;
							case 10:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"%s was bombarded by many concussive attacks from %s's mine. [%d]",pr->callsign.c_str(),kr->callsign.c_str(),CountMines());
							}break;
							case 11:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"%s was ignited by %s's mine. [%d]",pr->callsign.c_str(),kr->callsign.c_str(),CountMines());
							}break;
							case 12:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"%s's mine bursted %s's tank to bite-size flaming pieces. [%d]",kr->callsign.c_str(),pr->callsign.c_str(),CountMines());
							}break;
							case 13:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"%s took a nosedive into %s's mine. [%d]",pr->callsign.c_str(),kr->callsign.c_str(),CountMines());
							}break;
							case 14:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"%s fell face first into %s's mine. [%d]",pr->callsign.c_str(),kr->callsign.c_str(),CountMines());
							}break;
							case 15:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"I knew %s would be clumsy enough to run into %s's mine. [%d]",pr->callsign.c_str(),kr->callsign.c_str(),CountMines());
							}break;
							case 16:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"%s killed %s with a mine. No surprise there. [%d]",kr->callsign.c_str(),pr->callsign.c_str(),CountMines());
							}break;
							case 17:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"DID YOU SEE THAT? %s did total carnage to %s's tank with that one little mine. [%d]",kr->callsign.c_str(),pr->callsign.c_str(),CountMines());
							}break;
							case 18:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"%s purposely ran into %s's mine. [%d]",pr->callsign.c_str(),kr->callsign.c_str(),CountMines());
							}break;
							case 19:{
								bz_sendTextMessagef(BZ_SERVER,BZ_ALLUSERS,"I ascertain that %s has been ruptured by a mine created from the heavens with the name dubbed %s. [%d]",pr->callsign.c_str(),kr->callsign.c_str(),CountMines());
							}break;
						}
						}
						if (pr) {
					bz_freePlayerRecord(pr);}
					if (kr) {
					bz_freePlayerRecord(kr);
					}
					}
				}
			}
		}break;
		case bz_ePlayerSpawnEvent: {
			playerID=((bz_PlayerSpawnEventData_V1*)eventData)->playerID;
			safetytime[playerID]=bz_getCurrentTime()+spawnsafetime; //Give a grace time on spawn.
		}break;
	}
}
<commit_msg>Complete rewrite of the plug-in and it works on the first try; the one commit wonder<commit_after>/*
UselessMine
    Copyright (C) 2014 Vladimir "allejo" Jimenez

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <memory>
#include <stdlib.h>

#include "bzfsAPI.h"
#include "bztoolkit/bzToolkitAPI.h"

// Define plugin name
const std::string PLUGIN_NAME = "Useless Mine";

// Define plugin version numbering
const int MAJOR = 1;
const int MINOR = 0;
const int REV = 0;
const int BUILD = 8;

class UselessMine : public bz_Plugin, public bz_CustomSlashCommandHandler
{
public:
    virtual const char* Name ();
    virtual void Init (const char* config);
    virtual void Event (bz_EventData *eventData);
    virtual void Cleanup (void);

    virtual bool SlashCommand (int playerID, bz_ApiString, bz_ApiString, bz_APIStringList*);

    virtual int  getMineCount ();
    virtual void initializeMessages (void),
                 removeAllMines(int playerID),
                 removeMine (int mineIndex),
                 setMine (int owner, float pos[3], bz_eTeamType team);

    // The information each mine will contain
    struct Mine
    {
        int owner, victim; // The owner of the mine and the victim, respectively

        float x, y, z;     // The coordinates of where the mine was placed

        bz_eTeamType team; // The team of the owner

        bool detonated;    // Whether or not the mine has been detonated; to prepare it for removal from play

        Mine (int _owner, float _pos[3], bz_eTeamType _team) :
            owner(_owner),
            victim(-1),
            x(_pos[0]),
            y(_pos[1]),
            z(_pos[2]),
            team(_team),
            detonated(false)
        {}
    };

    std::vector<Mine>        activeMines;   // A vector that will store all of the mines that are in play
    std::vector<std::string> deathMessages; // A vector that will store all of the witty death messages

    double bzdb_SpawnSafetyTime, // The BZDB variable that will store the amount of seconds a player has before a mine is detonated
           playerSpawnTime[256]; // The time of a player's last spawn time used to calculate their safety from detonation
};

BZ_PLUGIN(UselessMine)

const char* UselessMine::Name (void)
{
    static std::string pluginBuild = "";

    if (!pluginBuild.size())
    {
        std::ostringstream pluginBuildStream;

        pluginBuildStream << PLUGIN_NAME << " " << MAJOR << "." << MINOR << "." << REV << " (" << BUILD << ")";
        pluginBuild = pluginBuildStream.str();
    }

    return pluginBuild.c_str();
}

void UselessMine::Init (const char* commandLine)
{
    // Register our events with Register()
    Register(bz_eFlagGrabbedEvent);
    Register(bz_ePlayerDieEvent);
    Register(bz_ePlayerPartEvent);
    Register(bz_ePlayerSpawnEvent);
    Register(bz_ePlayerUpdateEvent);

    // Register our custom slash commands
    bz_registerCustomSlashCommand("mine", this);

    // Initialize all of the witty death messages
    initializeMessages();

    // Set some custom BZDB variables
    bzdb_SpawnSafetyTime = bztk_registerCustomDoubleBZDB("_mineSafetyTime", 5.0);
}

void UselessMine::Cleanup (void)
{
    Flush(); // Clean up all the events

    // Clean up our custom slash commands
    bz_removeCustomSlashCommand("mine");
}

void UselessMine::Event (bz_EventData *eventData)
{
    switch (eventData->eventType)
    {
        case bz_eFlagGrabbedEvent: // This event is called each time a flag is grabbed by a player
        {
            bz_FlagGrabbedEventData_V1* flagGrabData = (bz_FlagGrabbedEventData_V1*)eventData;

            // Data
            // ---
            //    (int)           playerID  - The player that grabbed the flag
            //    (int)           flagID    - The flag ID that was grabbed
            //    (bz_ApiString)  flagType  - The flag abbreviation of the flag that was grabbed
            //    (float[3])      pos       - The position at which the flag was grabbed
            //    (double)        eventTime - This value is the local server time of the event.

            // If the user grabbed the Useless flag, let them know they can place a mine
            if (strcmp(flagGrabData->flagType, "US") == 0)
            {
                bz_sendTextMessage(BZ_SERVER, flagGrabData->playerID, "You grabbed a Useless flag! Type /mine at any time to set a useless mine!");
            }
        }
        break;

        case bz_ePlayerDieEvent: // This event is called each time a tank is killed.
        {
            bz_PlayerDieEventData_V1* dieData = (bz_PlayerDieEventData_V1*)eventData;

            // Data
            // ---
            //   (int)                   playerID       - ID of the player who was killed.
            //   (bz_eTeamType)          team           - The team the killed player was on.
            //   (int)                   killerID       - The owner of the shot that killed the player, or BZ_SERVER for server side kills
            //   (bz_eTeamType)          killerTeam     - The team the owner of the shot was on.
            //   (bz_ApiString)          flagKilledWith - The flag name the owner of the shot had when the shot was fired.
            //   (int)                   shotID         - The shot ID that killed the player, if the player was not killed by a shot, the id will be -1.
            //   (bz_PlayerUpdateState)  state          - The state record for the killed player at the time of the event
            //   (double)                eventTime      - Time of the event on the server.

            int playerID = dieData->playerID;

            // Loop through all the mines in play
            for (int i = 0; i < getMineCount(); i++)
            {
                // Create a local variable for easy access
                Mine &detonatedMine = activeMines.at(i);

                // Check if the mine has already been detonated
                if (detonatedMine.detonated)
                {
                    // Check if the victim killed is the player who just died
                    if (detonatedMine.victim == playerID)
                    {
                        // Check if the player who just died was killed by the server
                        if (dieData->killerID == 253)
                        {
                            // The random number used to fetch a random taunting death message
                            int randomNumber = rand() % deathMessages.size();

                            // Get the callsigns of the players
                            const char* owner  = bz_getPlayerCallsign(detonatedMine.owner);
                            const char* victim = bz_getPlayerCallsign(detonatedMine.victim);

                            // Attribute the kill to the mine owner
                            dieData->killerID = detonatedMine.owner;

                            // This mine has been detonated and we're done with the information that we need
                            removeMine(i);

                            bz_sendTextMessagef(BZ_SERVER, BZ_ALLUSERS, deathMessages.at(randomNumber).c_str(), owner, victim);
                            break;
                        }
                    }
                }
            }
        }
        break;

        case bz_ePlayerPartEvent: // This event is called each time a player leaves a game
        {
            bz_PlayerJoinPartEventData_V1* partData = (bz_PlayerJoinPartEventData_V1*)eventData;

            // Data
            // ---
            //    (int)                   playerID  - The player ID that is leaving
            //    (bz_BasePlayerRecord*)  record    - The player record for the leaving player
            //    (bz_ApiString)          reason    - The reason for leaving, such as a kick or a ban
            //    (double)                eventTime - Time of event.

            int playerID = partData->playerID;

            removeAllMines(playerID);
        }
        break;

        case bz_ePlayerSpawnEvent: // This event is called each time a playing tank is being spawned into the world
        {
            bz_PlayerSpawnEventData_V1* spawnData = (bz_PlayerSpawnEventData_V1*)eventData;

            // Data
            // ---
            //    (int)                   playerID  - ID of the player who was added to the world.
            //    (bz_eTeamType)          team      - The team the player is a member of.
            //    (bz_PlayerUpdateState)  state     - The state record for the spawning player
            //    (double)                eventTime - Time local server time for the event.

            int playerID = spawnData->playerID;

            // Save the time the player spawned last
            playerSpawnTime[playerID] = bz_getCurrentTime();
        }
        break;

        case bz_ePlayerUpdateEvent: // This event is called each time a player sends an update to the server
        {
            bz_PlayerUpdateEventData_V1* updateData = (bz_PlayerUpdateEventData_V1*)eventData;

            // Data
            // ---
            //   (int)       playerID  - ID of the player that sent the update
            //   (float[3])  pos       - The player's current position
            //   (float[3])  velocity  - The player's current velocity
            //   (float)     azimuth   - The direction the player is facing
            //   (float)     angvel    - The player's angular velocity
            //   (int)       phydrv    - The physics driver the player is on
            //   (double)    eventTime - The current server time

            int playerID = updateData->playerID;

            // Loop through all of the players
            for (int i = 0; i < getMineCount(); i++)
            {
                // Make an easy access mine
                Mine &currentMine = activeMines.at(i);

                // If the mine owner is not the player triggering the mine (so no self kills) and the player is a rogue or does is an enemy team relative to the mine owner
                if (currentMine.owner != playerID && (bz_getPlayerTeam(playerID) == eRogueTeam || bz_getPlayerTeam(playerID) != currentMine.team))
                {
                    // Make easy to access variables
                    float  playerPos[3] = {updateData->state.pos[0], updateData->state.pos[1], updateData->state.pos[2]};
                    double shockRange   = bz_getBZDBDouble("_shockOutRadius") * 0.75;

                    // Check if the player is in the detonation range
                    if ((playerPos[0] > currentMine.x - shockRange && playerPos[0] < currentMine.x + shockRange) &&
                        (playerPos[1] > currentMine.y - shockRange && playerPos[1] < currentMine.y + shockRange) &&
                        (playerPos[2] > currentMine.z - shockRange && playerPos[2] < currentMine.z + shockRange) &&
                        playerSpawnTime[playerID] + bzdb_SpawnSafetyTime <= bz_getCurrentTime() && !currentMine.detonated)
                    {
                        // Check that the mine owner exists and is not an observer
                        if (bztk_isValidPlayerID(currentMine.owner) && bz_getPlayerTeam(currentMine.owner) != eObservers)
                        {
                            // Get the current mine position
                            float minePos[3] = {currentMine.x, currentMine.y, currentMine.z};

                            // Save who detonated the mine and mark it as detonated
                            currentMine.victim    = playerID;
                            currentMine.detonated = true;

                            // BOOM!
                            bz_fireWorldWep("SW", 2.0, BZ_SERVER, minePos, 0, 0, 0, currentMine.team);
                        }
                        // Just in case the player doesn't exist or is an observer, then remove the mine because it shouldn't be there
                        else
                        {
                            removeMine(i);
                        }

                        break;
                    }
                }
            }
        }
        break;

        default: break;
    }
}

bool UselessMine::SlashCommand(int playerID, bz_ApiString command, bz_ApiString /*message*/, bz_APIStringList *params)
{
    if (command == "mine")
    {
        std::shared_ptr<bz_BasePlayerRecord> playerRecord(bz_getPlayerByIndex(playerID));

        // If the player is not an observer, they let them proceed to the next check
        if (playerRecord->team != eObservers)
        {
            // Check if the player has the Useless flag
            if (playerRecord->currentFlag == "USeless (+US)")
            {
                // Store their current position
                float currentPosition[3] = {playerRecord->lastKnownState.pos[0], playerRecord->lastKnownState.pos[1], playerRecord->lastKnownState.pos[2]};

                setMine(playerID, currentPosition, playerRecord->team);
            }
            else
            {
                bz_sendTextMessage(BZ_SERVER, playerID, "You can't place a mine without the Useless flag!");
            }
        }
        else
        {
            bz_sendTextMessage(BZ_SERVER, playerID, "Silly observer, you can't place a mine.");
        }

        return true;
    }
}

// A shortcut to get the amount of mines that are in play
int UselessMine::getMineCount()
{
    return activeMines.size();
}

// In order to keep things organized, this function is where you can specify all the witty death messages you want to be available
void UselessMine::initializeMessages()
{
    deathMessages.push_back("%s was killed by %s's mine.");
    deathMessages.push_back("%s was owned by %s's mine.");
    deathMessages.push_back("%s was obliterated by %s's mine.");
    deathMessages.push_back("%s's tank disintegrated from %s's mine.");
    deathMessages.push_back("%s was permanently blinded by the bright light from %s's mine.");
    deathMessages.push_back("%s was sent shooting into the stars by %s's mine.");
    deathMessages.push_back("%s was never heard from again thanks to %s's mine.");
    deathMessages.push_back("We salute %s for taking an atrocious hit from %s's mine.");
    deathMessages.push_back("%s's mine left %s's tank parts scattered all over.");
    deathMessages.push_back("%s thought %s's mine was a shiny brand new car.");
    deathMessages.push_back("%s was bombarded by many concussive attacks from %s's mine.");
    deathMessages.push_back("%s was ignited by %s's mine.");
    deathMessages.push_back("%s's mine bursted %s's tank to bite-size flaming pieces.");
    deathMessages.push_back("%s took a nosedive into %s's mine.");
    deathMessages.push_back("%s fell face first into %s's mine.");
    deathMessages.push_back("I knew %s would be clumsy enough to run into %s's mine.");
    deathMessages.push_back("%s killed %s with a mine. No surprise there.");
    deathMessages.push_back("DID YOU SEE THAT? %s did total carnage to %s's tank with that one little mine.");
    deathMessages.push_back("%s purposely ran into %s's mine.");
    deathMessages.push_back("I ascertain that %s has been ruptured by a mine created from the heavens with the name dubbed %s.");
}

void UselessMine::removeAllMines(int playerID)
{
    // Go through all of the mines
    for (int i = 0; i < getMineCount(); i++)
    {
        // Quick access mine
        Mine &currentMine = activeMines.at(i);

        // If the mine belongs to the player, remove it
        if (currentMine.owner == playerID)
        {
            removeMine(i);
        }
    }
}

// A shortcut to remove a mine from play
void UselessMine::removeMine(int mineIndex)
{
    activeMines.erase(activeMines.begin() + mineIndex);
}

// A shortcut to set a mine
void UselessMine::setMine(int owner, float pos[3], bz_eTeamType team)
{
    // Remove their flag because it's going to be a US flag
    bz_removePlayerFlag(owner);

    // Push the new mine
    Mine newMine(owner, pos, team);
    activeMines.push_back(newMine);
}<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed 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.

#include "time_zone_fixed.h"

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>

namespace cctz {

namespace {

// The prefix used for the internal names of fixed-offset zones.
const char kFixedOffsetPrefix[] = "Fixed/";

int Parse02d(const char* p) {
  const char kDigits[] = "0123456789";
  if (const char* ap = std::strchr(kDigits, *p)) {
    int v = static_cast<int>(ap - kDigits);
    if (const char* bp = std::strchr(kDigits, *++p)) {
      return (v * 10) + static_cast<int>(bp - kDigits);
    }
  }
  return -1;
}

}  // namespace

bool FixedOffsetFromName(const std::string& name, int* seconds) {
  if (name.compare(0, std::string::npos, "UTC", 3) == 0) {
    *seconds = 0;
    return true;
  }

  const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
  const char* const ep = kFixedOffsetPrefix + prefix_len;
  if (name.size() != prefix_len + 12)  // "<prefix>UTC+99:99:99"
    return false;
  if (!std::equal(kFixedOffsetPrefix, ep, name.begin()))
    return false;
  const char* np = name.data() + prefix_len;
  if (*np++ != 'U' || *np++ != 'T' || *np++ != 'C')
    return false;
  if (np[0] != '+' && np[0] != '-')
    return false;
  if (np[3] != ':' || np[6] != ':')  // see note below about large offsets
    return false;

  int hours = Parse02d(np + 1);
  if (hours == -1) return false;
  int mins = Parse02d(np + 4);
  if (mins == -1) return false;
  int secs = Parse02d(np + 7);
  if (secs == -1) return false;

  secs += ((hours * 60) + mins) * 60;
  if (secs > 24 * 60 * 60) {
    // We don't support fixed-offset zones more than 24 hours away from
    // UTC in order to avoid problems in rendering such offsets using
    // %z, and also to limit the total number of zones.
    return false;
  }
  *seconds = secs * (np[0] == '-' ? -1 : 1);  // "-" means west
  return true;
}

std::string FixedOffsetToName(int seconds) {
  if (seconds == 0) return "UTC";
  const char sign = (seconds < 0 ? '-' : '+');
  int minutes = seconds / 60;
  seconds %= 60;
  if (sign == '-') {
    if (seconds > 0) {
      seconds -= 60;
      minutes += 1;
    }
    seconds = -seconds;
    minutes = -minutes;
  }
  int hours = minutes / 60;
  minutes %= 60;
  char buf[sizeof(kFixedOffsetPrefix) + sizeof("UTC-596523:14:08")];
  std::snprintf(buf, sizeof(buf), "%sUTC%c%02d:%02d:%02d",
	        kFixedOffsetPrefix, sign, hours, minutes, seconds);
  return buf;
}

std::string FixedOffsetToAbbr(int seconds) {
  std::string abbr = FixedOffsetToName(seconds);
  const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
  const char* const ep = kFixedOffsetPrefix + prefix_len;
  if (abbr.size() >= prefix_len) {
    if (std::equal(kFixedOffsetPrefix, ep, abbr.begin())) {
      abbr.erase(0, prefix_len);
      if (abbr.size() == 12) {                     // UTC+99:99:99
        abbr.erase(9, 1);                          // UTC+99:9999
        abbr.erase(6, 1);                          // UTC+999999
        if (abbr[8] == '0' && abbr[9] == '0') {    // UTC+999900
          abbr.erase(8, 2);                        // UTC+9999
          if (abbr[6] == '0' && abbr[7] == '0') {  // UTC+9900
            abbr.erase(6, 2);                      // UTC+99
            if (abbr[4] == '0') {                  // UTC+09
              abbr.erase(4, 1);                    // UTC+9
            }
          }
        }
      }
    }
  }
  return abbr;
}

}  // namespace cctz
<commit_msg>Remove TAB character that slipped in during previous commit.<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed 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.

#include "time_zone_fixed.h"

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>

namespace cctz {

namespace {

// The prefix used for the internal names of fixed-offset zones.
const char kFixedOffsetPrefix[] = "Fixed/";

int Parse02d(const char* p) {
  const char kDigits[] = "0123456789";
  if (const char* ap = std::strchr(kDigits, *p)) {
    int v = static_cast<int>(ap - kDigits);
    if (const char* bp = std::strchr(kDigits, *++p)) {
      return (v * 10) + static_cast<int>(bp - kDigits);
    }
  }
  return -1;
}

}  // namespace

bool FixedOffsetFromName(const std::string& name, int* seconds) {
  if (name.compare(0, std::string::npos, "UTC", 3) == 0) {
    *seconds = 0;
    return true;
  }

  const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
  const char* const ep = kFixedOffsetPrefix + prefix_len;
  if (name.size() != prefix_len + 12)  // "<prefix>UTC+99:99:99"
    return false;
  if (!std::equal(kFixedOffsetPrefix, ep, name.begin()))
    return false;
  const char* np = name.data() + prefix_len;
  if (*np++ != 'U' || *np++ != 'T' || *np++ != 'C')
    return false;
  if (np[0] != '+' && np[0] != '-')
    return false;
  if (np[3] != ':' || np[6] != ':')  // see note below about large offsets
    return false;

  int hours = Parse02d(np + 1);
  if (hours == -1) return false;
  int mins = Parse02d(np + 4);
  if (mins == -1) return false;
  int secs = Parse02d(np + 7);
  if (secs == -1) return false;

  secs += ((hours * 60) + mins) * 60;
  if (secs > 24 * 60 * 60) {
    // We don't support fixed-offset zones more than 24 hours away from
    // UTC in order to avoid problems in rendering such offsets using
    // %z, and also to limit the total number of zones.
    return false;
  }
  *seconds = secs * (np[0] == '-' ? -1 : 1);  // "-" means west
  return true;
}

std::string FixedOffsetToName(int seconds) {
  if (seconds == 0) return "UTC";
  const char sign = (seconds < 0 ? '-' : '+');
  int minutes = seconds / 60;
  seconds %= 60;
  if (sign == '-') {
    if (seconds > 0) {
      seconds -= 60;
      minutes += 1;
    }
    seconds = -seconds;
    minutes = -minutes;
  }
  int hours = minutes / 60;
  minutes %= 60;
  char buf[sizeof(kFixedOffsetPrefix) + sizeof("UTC-596523:14:08")];
  std::snprintf(buf, sizeof(buf), "%sUTC%c%02d:%02d:%02d",
                kFixedOffsetPrefix, sign, hours, minutes, seconds);
  return buf;
}

std::string FixedOffsetToAbbr(int seconds) {
  std::string abbr = FixedOffsetToName(seconds);
  const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
  const char* const ep = kFixedOffsetPrefix + prefix_len;
  if (abbr.size() >= prefix_len) {
    if (std::equal(kFixedOffsetPrefix, ep, abbr.begin())) {
      abbr.erase(0, prefix_len);
      if (abbr.size() == 12) {                     // UTC+99:99:99
        abbr.erase(9, 1);                          // UTC+99:9999
        abbr.erase(6, 1);                          // UTC+999999
        if (abbr[8] == '0' && abbr[9] == '0') {    // UTC+999900
          abbr.erase(8, 2);                        // UTC+9999
          if (abbr[6] == '0' && abbr[7] == '0') {  // UTC+9900
            abbr.erase(6, 2);                      // UTC+99
            if (abbr[4] == '0') {                  // UTC+09
              abbr.erase(4, 1);                    // UTC+9
            }
          }
        }
      }
    }
  }
  return abbr;
}

}  // namespace cctz
<|endoftext|>