// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; -*-
////////////////////////////////////////////////////////////////////
//
// $Id: closed_list.cpp 839 2011-10-12 19:49:17Z Sebastian Kupferschmid $
//
////////////////////////////////////////////////////////////////////

#include "closed_list.h"
#include "system/state.h"
#include <utility>

using namespace std;

bool ClosedList::equal(const State* s1, const State* s2) const {
    return s1->discEqual(s2);
}

const State* ClosedList::insert(State* state) {
    pair<hash_t::iterator, bool> pos = states.insert(make_pair(state->hashKey(), list_t()));
    
    list_t& l = pos.first->second;
    for (list_t::iterator it = l.begin(); it != l.end(); ++it) {
	if (!equal(*it, state)) {
	    continue;
	}
	state->share(*it);

	switch ((*it)->zone().relation(state->zone()))
	{
	case base_SUPERSET:  // state < *it
	case base_EQUAL:     // state == *it
	    return *it;
	case base_SUBSET:    // *it < state
	    it = l.erase(it);
	    l.push_front(state);
	    ++nrStates;
	    return NULL;
	case base_DIFFERENT: // state & *it == 0
	    break;
	}
    }
    l.push_front(state);
    ++nrStates;
    return NULL;
}

const State* ClosedList::contains(const State* state) const {
    hash_t::const_iterator pos = states.find(state->hashKey());
    if (pos == states.end()) {
	return NULL;
    }
    const list_t& l = pos->second;
    
    for (list_t::const_iterator it = l.begin(); it != l.end(); ++it) {
	if (!equal(*it, state)) {
	    continue;
	}
	switch ((*it)->zone().relation(state->zone()))
	{
	case base_SUPERSET:  // state < *it
	case base_EQUAL:     // state == it
	    return *it;
	case base_SUBSET:    // *it < state
	case base_DIFFERENT: // state & *it == 0
	    break;
	}
    }
    return NULL;
}

////////////////////////////////////////////////////////////

const State* AStarClosedList::insert(State* state) {
    pair<hash_t::iterator, bool> pos = states.insert(make_pair(state->hashKey(), list_t()));
    
    list_t& l = pos.first->second;
    for (list_t::iterator it = l.begin(); it != l.end(); ++it) {
	if (!equal(*it, state)) {
	    continue;
	}
	state->share(*it);
	
	switch ((*it)->zone().relation(state->zone()))
	{
	case base_SUPERSET:  // state < *it
	    if ((*it)->extra(depth) <= state->extra(depth))
		return *it;
	    else
		break;
	case base_EQUAL:     // state == *it
	    return *it;
	case base_SUBSET:    // *it < state
	    if ((*it)->extra(depth) >= state->extra(depth)) {
		it = l.erase(it);
		l.push_front(state);
		++nrStates;
		return NULL;
	    }
	    else
		break;
	case base_DIFFERENT: // state & *it == 0
	    break;
	}
    }
    l.push_front(state);
    ++nrStates;
    return NULL;
    
}

const State* AStarClosedList::contains(const State* state) const {

    hash_t::const_iterator pos = states.find(state->hashKey());
    if (pos == states.end()) {
	return NULL;
    }
    const list_t& l = pos->second;
    
    for (list_t::const_iterator it = l.begin(); it != l.end(); ++it) {
	if (!equal(*it, state)) {
	    continue;
	}
	switch ((*it)->zone().relation(state->zone()))
	{
	case base_SUPERSET:  // state < *it
	    break;
	case base_EQUAL:     // state == it
	    return *it;
	case base_SUBSET:    // *it < state
	case base_DIFFERENT: // state & *it == 0
	    break;
	}
    }
    return NULL;
    
}


