// 	Copyright 06/22/01 Sun Microsystems, Inc. All Rights Reserved.

#pragma ident  "@(#)jidm_proxy_agent_impl.cc	1.6E% Sun Microsystems"

#include "cgw_utils/cgw_utils.hh"
#include "cgw_utils/cgw_global.hh"

#include "rgw_debug.hh"
#include "rgw_utils.hh"
#include "jidm_proxy_agent_impl.hh"


JIDMProxyAgentImpl::JIDMProxyAgentImpl() throw() 
	: refcnt_(1)
{
	rwlock_init(&proxy_agent_refcnt_lock_,NULL,NULL);
}


JIDMProxyAgentImpl::JIDMProxyAgentImpl(
    const JIDMProxyAgentImpl& rhs
) throw() 
{
    rgw_trace.print("JIDM::ProxyAgent - copy ctor\n");
	rwlock_init(&proxy_agent_refcnt_lock_,NULL,NULL);	
    if (this != &rhs) {
	refcnt_ = rhs.refcnt_ ; 
#if defined(ORBACUS) || defined(ORBIX)
	access_criteria_ = new JIDM::Criteria(rhs.access_criteria_);
#else
	access_criteria_ =
	    JIDM::Criteria::_duplicate(rhs.access_criteria_);
#endif
	finder_controller_ =
	    JIDM::ProxyAgentController::_duplicate(rhs.finder_controller_);
    }
}


JIDMProxyAgentImpl&
JIDMProxyAgentImpl::operator=(
    const JIDMProxyAgentImpl& rhs
) throw() {
    rgw_trace.print("JIDM::ProxyAgent - assignment operator\n");
	rwlock_init(&proxy_agent_refcnt_lock_,NULL,NULL);
    if (this != &rhs) {
	refcnt_ = rhs.refcnt_ ; 
#if defined(ORBACUS) || defined(ORBIX) 
	 access_criteria_ = new JIDM::Criteria(rhs.access_criteria_);
#else
	access_criteria_ =
	    JIDM::Criteria::_duplicate(rhs.access_criteria_);
#endif
	finder_controller_ =
	    JIDM::ProxyAgentController::_duplicate(rhs.finder_controller_);
    }
    return *this;
}


int
JIDMProxyAgentImpl::operator==(
    const JIDMProxyAgentImpl& rhs
) throw() {
    rgw_trace.print("JIDM::ProxyAgent - equal [==] operator\n");
    if ((NULL != &rhs) && (this != &rhs)) {
	if(!RGWUtils::jidm_criterias_match(
	    access_criteria_,
	    rhs.access_criteria_))
	{
	    return 0;
	}
	CORBA::String_var criteria1_str =
	    CGWGlobal::orb_->object_to_string(finder_controller_);
	CORBA::String_var criteria2_str = 
	    CGWGlobal::orb_->object_to_string(rhs.finder_controller_);
	if(!CGWUtils::equal(criteria1_str, criteria2_str))
	{
	    return 0;
	}
    }
    return 1;
}

// JIDMProxyAgentImpl ctor extracts and stores the ProxyAgentController
// associated with ProxyAgentFinder object
JIDMProxyAgentImpl::JIDMProxyAgentImpl(
    const JIDM::Criteria& the_criteria
) throw(
    JIDM::InvalidCriteria
) : refcnt_(1)
 {
    rgw_trace.print("JIDMProxyAgentImpl::JIDMProxyAgentImpl() start\n");
	rwlock_init(&proxy_agent_refcnt_lock_,NULL,NULL);

    CORBA::ULong len = the_criteria.length();
    if (0 == len) {
	rgw_error.print("JIDM::ProxyAgent Access Criteria is empty\n");
	throw JIDM::InvalidCriteria();
    }

    // JIDM::Criteria passed to the ctor contains an additional NVPair which
    // supplies the Proxy Agent Controller Object Reference of the associated
    // Proxy Agent Finder Object. This is separated out of the client access
    // criteria and stored locally.
    access_criteria_ = new JIDM::Criteria(len-1);
    access_criteria_->length(len-1);
    for (unsigned short i = 0; i < len-1; ++i) {
	access_criteria_[i] = the_criteria[i];
    }

    if (!CGWUtils::equal(the_criteria[i].name,
			 CGWGlobal::JIDM_CONTROLLER_REFERENCE)
    ) {
	rgw_error.print("Internal Error : Finder Controller missing\n");
	throw JIDM::InvalidCriteria();
    }

    JIDM::ProxyAgentController_ptr pac;
    if (!(the_criteria[i].value >>= pac)) {
	rgw_error.print("Internal Error : Finder Controller non existent\n");
	throw JIDM::InvalidCriteria();
    }
    finder_controller_ = JIDM::ProxyAgentController::_duplicate(pac);

    rgw_trace.print("JIDMProxyAgentImpl::JIDMProxyAgentImpl() end\n");
}

JIDMProxyAgentImpl::~JIDMProxyAgentImpl() throw() {
    rgw_trace.print("JIDMProxyAgentImpl::~JIDMProxyAgentImpl() start()\n");
	rwlock_destroy(&proxy_agent_refcnt_lock_);
}

// access_criteria returns the client supplied access_criteria
JIDM::Criteria*
JIDMProxyAgentImpl::access_criteria() throw (CORBA::SystemException) {
    rgw_trace.print("JIDMProxyAgentImpl::access_criteria() start\n");
    
    return new JIDM::Criteria(access_criteria_);
}


// destory takes as input the destruction mode and supplied user criteria
// and validates and executes the destruction of the proxy_agent
JIDM::Criteria*
JIDMProxyAgentImpl::destroy(
    JIDM::ProxyAgent::DestructionMode mode,
    const JIDM::Criteria& criteria
) throw (
    JIDM::InvalidCriteria,
    JIDM::CannotMeetCriteria,
    CORBA::SystemException
) {
    rgw_trace.print("JIDMProxyAgentImpl::destroy() start\n");

    JIDM::Criteria destroy_criteria = access_criteria_;
    
    CORBA::ULong len = access_criteria_->length();
    CORBA::ULong controller_count = 0;
    CORBA::ULong allowed_to_destroy_count = 0;

    JIDM::ProxyAgentController_ptr pac = JIDM::ProxyAgentController::_nil();
	
	if( (JIDM::ProxyAgent::gracefully == mode) && ( refcnt_ > 1 ))
	{
		rw_wrlock(&proxy_agent_refcnt_lock_);
		refcnt_ -- ; 
		rw_unlock(&proxy_agent_refcnt_lock_);		
		return new JIDM::Criteria(destroy_criteria);   
	}
    for(CORBA::ULong i = 0; i < len; ++i) {
	if(!strcmp(access_criteria_[i].name,
		   CGWGlobal::JIDM_CONTROLLER_REFERENCE))
	{
	    controller_count++;
	    if(CORBA::tk_null == access_criteria_[i].value.type()->kind()) {
		rgw_error.print(
		    "Unable to invoke destruction_is_allow on controllers: "
		    "criteria is empty\n"
		);
		break;
	    }

	    if (access_criteria_[i].value >>= pac) {
		if(pac->_non_existent()) {
		    rgw_error.print("Proxy Agent Controller non-existent\n");
		    break;
		}

		// Invoke destruction_is_allowed() on each controller object
		try {
		    if (pac->destruction_is_allowed(criteria))
			allowed_to_destroy_count++;
		}
		catch (const CORBA::Exception& e) {
 		    CGWUtils::print_corba_exception(
		    	rgw_error,
			"destruction_is_allowed() threw exception:\n ",
			e);

		    if(JIDM::ProxyAgent::gracefully == mode)
			throw;

		    return (JIDM::Criteria*)NULL;
		}
	    }
	}
    }

    if (controller_count == allowed_to_destroy_count) {
	// Delete EMApplicationInstance from SEM MIS

	// Invoke delete on all associated ProxyAgentController objects
	if (0 != controller_count) {
	    for(i = 0; i < len; ++i) {
		if(!strcmp(access_criteria_[i].name,
			   CGWGlobal::JIDM_CONTROLLER_REFERENCE)
		) {
		    pac = JIDM::ProxyAgentController::_nil();

		    if (access_criteria_[i].value >>= pac) {
			if(pac->_non_existent()) {
			    rgw_error.print(
				"Unable to invoke destroyed() on controllers: "
				"Proxy Agent Controller non existent\n");
			}
			pac->destroyed(criteria);
		    }
		}
	    }
	}

	// Remove JIDM::ProxyAgent from list
	finder_controller_->destroyed(destroy_criteria);
	
	return new JIDM::Criteria(destroy_criteria);
    }
    else {
	rgw_debug.print(
	    "One of the ProxyAgentControllers vetoed the destroy()\n");

	if (JIDM::ProxyAgent::gracefully == mode)
	    throw JIDM::InvalidCriteria();

	return (JIDM::Criteria*)NULL;
    }
    
}

void 
JIDMProxyAgentImpl::add_reference_()
{
	rw_wrlock(&proxy_agent_refcnt_lock_);
	refcnt_ ++ ; 
	rw_unlock(&proxy_agent_refcnt_lock_);	
}

CosNaming::NamingContext_ptr 
JIDMProxyAgentImpl::get_domain_naming_context() throw() {
    return CosNaming::NamingContext::_nil();
}

CosLifeCycle::FactoryFinder_ptr
JIDMProxyAgentImpl::get_domain_factory_finder() throw() {
    return CosLifeCycle::FactoryFinder::_nil();
}

