/**
 * @file
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.
 * In particular this file is part of the Framework Core Library
 *
 * The iWear Framework 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 as in version 2 of the License.

 * 
 * The iWear Framework 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
 * The iWear Framework; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <iwear-context/compositecontext.h>

#include <sstream>

using namespace std;

namespace iwear{
namespace context {
    CompositeContext::~CompositeContext(void)
    { 
    }

    void CompositeContext::add_child(ContextObject* co){
	// check if the context is already a child
	map<const string, ContextObject*>::iterator pos 
	    = children.find(co->get_name());
	if(pos != children.end()){
	    return;
	}
	// add this context as a parent of the child
	co->add_parent(this);
	// add the child this contexts children
	children.insert(pair<const string, ContextObject*>(co->get_name(), co));
	// check if we have to adjust the level of this context
	if(co->get_level() >= level){
	    check_level();
	}
    }

    void CompositeContext::remove_child(const string& name){
	map<const string, ContextObject*>::iterator pos 
	    = children.find(name);
	// check if we have such a child
	if(pos == children.end()){
	    return;
	}
	uint32_t childlevel = pos->second->get_level();
	// remove this context from the parents-list of the child-context to
	// be removed too
	pos->second->remove_parent(this->name);
	// erase the child
	children.erase(pos);

	// check if we eventually have to adjust our level - if necessary
	// parents will check too
	if(childlevel +1 == level){
	    check_level();
	}
    }

    void CompositeContext::check_level(void){
	map<const string, ContextObject*>::iterator it = children.begin();
	uint32_t max = 0;
	while(it != children.end()){
	    if(it->second->get_level() > max){
		max = it->second->get_level();
	    }
	    ++it;
	}
	if(max +1 != level){
	    // adjust our level
	    level = max +1;
	    // tell our parents to check their level
	    map<const string, ContextObject*>::iterator it2
		= parents.begin();
	    while(it2 != parents.end()){
		(static_cast<CompositeContext*>(it2->second))->check_level();
		++it2;
	    }
	}
    }

    bool CompositeContext::register_children(ContextManager* cm){
	map<const string, ContextObject*>::iterator it
	    = children.begin();
	bool ret = true;
	while(it != children.end()){
	    ret = cm->register_context(it->second) && ret;
	    ++it;
	}
	return ret;
    }

    vector<AtomicContext*> CompositeContext::get_related_atomics(void){
	vector<AtomicContext*> ret, tmp;
	map<const string, ContextObject*>::iterator it = children.begin();
	while(it != children.end()){
	    switch(it->second->get_context_type()){
		case COMPOSITE:
		    tmp = static_cast<CompositeContext*>(it->second)->get_related_atomics();
		    ret.insert(ret.end(), tmp.begin(), tmp.end());
		    break;
		case ATOMIC:
		    ret.push_back(static_cast<AtomicContext*>(it->second));
		    break;
		default:
		    stringstream stream;
		    stream << __FFL__ << ":\nfound an invalid in context object (" 
			   << it->second->get_name() << ") context-type: " 
			   << it->second->get_context_type() << endl;
		    throw consistency_error(stream.str());
	    } 
	    ++it;
	}
	return ret;
    }

} // namespace context
} // namespace iwear

