/***
*auto_handle.h
*
*       Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:   automatic resource management, like std::auto_ptr for ref classes
*
*       [Public]
*
****/

#pragma once

#if !defined(_INC_MSCLR_AUTO_HANDLE)

#ifndef __cplusplus_cli
#error ERROR: msclr libraries are not compatible with /clr:oldSyntax
#endif

#include <msclr\safebool.h>

namespace msclr
{

    // wrap a resource to enforce strict ownership and ensure proper cleanup
    template<typename _element_type>
    ref class auto_handle
    {
    private:
        // disallow explicit comparisons to _safe_bool
        bool operator==( _detail_class::_safe_bool );
        bool operator!=( _detail_class::_safe_bool );
        
    public:

        // Constructors
        
        auto_handle() 
            : m_handle( nullptr )
        {
        }

        // construct from object pointer
        auto_handle( _element_type ^ _ptr ) 
            : m_handle( _ptr )
        {
        }

        // construct by assuming pointer from _right auto_handle
        auto_handle(auto_handle<_element_type> % _right ) 
                : m_handle( _right.release() )
        {
        }

        template<typename _other_type>
        auto_handle( auto_handle<_other_type> % _right ) 
                : m_handle( _right.release() )
        {
        }

        // assign compatible _right
        auto_handle<_element_type> % operator=( 
            auto_handle<_element_type> % _right ) 
        {
            reset( _right.release() );
            return *this;
        }


        template<typename _other_type>
        auto_handle<_element_type> % operator=(
            auto_handle<_other_type> % _right ) 
        {
            reset( _right.release() );
            return *this;
        }

        _element_type ^ get()
        {
            return m_handle;
        }

        // return pointer to class object (assume pointer)
        _element_type ^ operator->()
        {
            return m_handle;
        }

        // for use when auto_handle appears in a conditional
        operator _detail_class::_safe_bool()
        {
            return valid() ? _detail_class::_safe_true : _detail_class::_safe_false;
        }

        // for use when auto_handle appears in a conditional
        bool operator!()
        {
            return ! valid();
        }


        template<typename _other_type>
        operator auto_handle<_other_type>() 
        {
            return auto_handle<_other_type>( *this );
        }

        void swap( auto_handle<_element_type> % _right ) 
        {
			auto_handle<_element_type> tmp = _right;
			_right = *this;
			*this = tmp;
        }

        void reset( _element_type ^ _new_ptr ) 
        {
            if( m_handle != _new_ptr )
            {
                if( valid() )
                {
                    delete m_handle;
                }
                m_handle = _new_ptr;
            }
        }

        void reset( ) 
        {
            reset(nullptr);
        }

        _element_type ^ release() 
        {
            _element_type ^_tmp_ptr = m_handle;
            m_handle = nullptr;
            return _tmp_ptr;
        }

        // destroy the object
        ~auto_handle()
        {
            if( valid() )
            {
                delete m_handle;
            }
        }

        private:

        bool valid()
        {
            // see if the managed resource is in the invalid state.
            return m_handle != nullptr;

        }

        // the wrapped object
        _element_type ^ m_handle;
    };

    // swap the contents of two auto_handle objects
    template<typename _element_type>
    void swap( auto_handle<_element_type> % _left, 
               auto_handle<_element_type> % _right ) 
    {
        _left.swap( _right );
    }

} // namespace msclr

#define _INC_MSCLR_AUTO_HANDLE

#endif // _INC_MSCLR_AUTO_HANDLE
