/*
 * e4refcount.cpp --
 *
 * The base class for all interface classes, manages reference counts.
 *
 *	Authors: Jacob Levy and Jean-Claude Wippler.
 *		 jyl@best.com	jcw@equi4.com
 *
 * This implementation is modelled after the c4_View class in Metakit.
 *
 * Copyright (c) 2000-2003, JYL Software Inc.
 * 
 * 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, EVEN IF
 * JYL SOFTWARE INC. IS MADE AWARE OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "e4graphimpl.h"

/*
 * This instance of e4_RefCount can be used by assigning it to fields or
 * variables of type e4_RefCount to remove remaining references to instances
 * that you want to discard. Especially useful for removing remaining
 * references in malloc'ed memory.
 */

e4_RefCount const invalidRefCount;

/*
 * Default constructor:
 */

e4_RefCount::e4_RefCount()
    : impl(NULL)
{
}

/*
 * Constructor which assigns a value to the implementation pointer.
 */

e4_RefCount::e4_RefCount(e4_RefCounter *ip)
    : impl(ip)
{
    if (impl != NULL) {
	impl->IncrRefCount();
    }
}

/*
 * Copying constructor:
 */

e4_RefCount::e4_RefCount(const e4_RefCount &referrer)
{
    impl = referrer.impl;
    if (impl != NULL) {
	impl->IncrRefCount();
    }
}

/*
 * Assignment operator:
 */

e4_RefCount & e4_RefCount::operator=(const e4_RefCount &referrer)
{
    /*
     * Only do the assignment if the referrer is of the same kind
     * as us.
     */

    if (Kind() != referrer.Kind()) {
	return *this;
    }

    /*
     * Do the assignment.
     */

    if (impl != referrer.impl) {
        if (impl != NULL) {
	    impl->DecrRefCount();
	}
	impl = referrer.impl;
	if (impl != NULL) {
	    impl->IncrRefCount();
	}
    }
    return *this;
}

/*
 * Destructor:
 */

e4_RefCount::~e4_RefCount()
{
    if (impl != NULL) {
	impl->DecrRefCount();
    }
}

/*
 * Return the current refcount. If the instance is invalid then
 * returns -1.
 */

int
e4_RefCount::RefCount() const
{
    if (impl == NULL) {
	return -1;
    }
    return impl->RefCount();
}

bool
e4_RefCount::IsValid() const
{
    if (impl == NULL) {
	return false;
    }
    return impl->IsValid();
}

/*
 * Comparison operators.
 */

bool
e4_RefCount::operator==(const e4_RefCount &compared) const
{
    /*
     * First check -- compare the two impl pointers. If they're
     * equal and non-NULL then the two instances are the same.
     */

    if ((impl != NULL) && (impl == compared.impl)) {
	return true;
    }

    /*
     * Handle invalid instances specially.
     */

    if (!IsValid()) {

        /*
	 * If the other instance is valid, then it can't be equal to this
	 * instance.
	 */

	if (compared.IsValid()) {
	    return false;
	}

	/*
	 * OK, the other one is also invalid, so we must compare the kind.
	 * They are equal only if both are invalid instances of the
	 * same kind.
	 */

	if (Kind() != compared.Kind()) {
	    return false;
	}

	/*
	 * All invalid instances of the same kind are equal.
	 */

	return true;
    }

    /*
     * This instance is valid, so to be equal, its impl pointer must be
     * the same as the other instance.
     */

    if (impl == compared.impl) {
        return true;
    }

    /*
     * Not equal:
     */

    return false;
}

bool
e4_RefCount::operator!=(const e4_RefCount &compared) const
{
    /*
     * First check -- compare the two impl pointers. If they're
     * equal and non-NULL then the two instances are the same.
     */

    if ((impl != NULL) && (impl == compared.impl)) {
	return false;
    }

    /*
     * Handle invalid instances specially:
     */

    if (!IsValid()) {

	/*
	 * If the other instance is valid, they are not equal, so return
	 * true.
	 */

	if (compared.IsValid()) {
	    return true;
	}

	/*
	 * The other instance is also invalid. To determine equality we
	 * must compare the two instances' kind. If their kinds are not
	 * equal, then this operator is true.
	 */

	if (Kind() != compared.Kind()) {
	    return true;
	}

	/*
	 * All invalid instances of the same kind are equal, so return false.
	 */

	return false;
    }

    /*
     * Both instances are valid, so to be inequal their impl pointers must
     * be different.
     */

    if (impl != compared.impl) {
        return true;
    }

    /*
     * The two instances turn out to be equal:
     */

    return false;
}

/*
 * Return the kind identifier for this instance. This should be overridden
 * by classes deriving from e4_RefCount.
 */

e4_RefKind
e4_RefCount::Kind() const
{
    return E4_RKINVALID;
}

/*
 * Set and get user level data associated with each instance.
 */

void
e4_RefCount::SetTransientUserData(void *data) const
{
    if (impl != NULL) {
	impl->SetTransientUserData(data);
    }
}

void *
e4_RefCount::GetTransientUserData() const
{
    if (impl == NULL) {
	return NULL;
    }
    return impl->GetTransientUserData();
}

