/*
 * e4pvisitor.cpp --
 *
 *	Implementation of the e4_ParentVisitor class defined in e4graph.h.
 *
 *	Authors: Jacob Levy and Jean-Claude Wippler.
 *		 jyl@best.com	jcw@equi4.com
 *
 * Copyright (c) 2000-2004, 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"

/*
 * Default constructor:
 */

e4_ParentVisitor::e4_ParentVisitor()
    : done(true),
      n(invalidNode),
      p(invalidNode),
      curParent(-1),
      s(invalidStorage)
{
}

/*
 * Copying constructor:
 */

e4_ParentVisitor::e4_ParentVisitor(const e4_ParentVisitor &referrer)
    : done(referrer.done),
      s(referrer.s),
      p(referrer.p),
      curParent(referrer.curParent),
      n(referrer.n)
{
}

/*
 * Assignment operator:
 */

e4_ParentVisitor &
e4_ParentVisitor::operator=(const e4_ParentVisitor &referrer)
{
    done = referrer.done;
    s = referrer.s;
    p = referrer.p;
    curParent = referrer.curParent;
    n = referrer.n;

    return * this;
}

/*
 * Comparison operators:
 */

bool
e4_ParentVisitor::operator==(const e4_ParentVisitor &compared) const
{
    if ((done == compared.done) &&
	(s == compared.s) &&
	(p == compared.p) &&
	(curParent == compared.curParent) &&
	(n == compared.n)) {
	return true;
    }
    return false;
}

bool
e4_ParentVisitor::operator!=(const e4_ParentVisitor &compared) const
{
    if ((done == compared.done) &&
	(s == compared.s) &&
	(p == compared.p) &&
	(curParent == compared.curParent) &&
	(n == compared.n)) {
	return false;
    }
    return true;
}

/*
 * Constructors that initialize the visitor from a node.
 */

e4_ParentVisitor::e4_ParentVisitor(const e4_Node &nn)
    : done(true)
{
    SetNode(nn);
}

/*
 * Destructor:
 */

e4_ParentVisitor::~e4_ParentVisitor()
{
    s = invalidStorage;
    n = invalidNode;
    p = invalidNode;
    curParent = -1;
}

bool
e4_ParentVisitor::SetNode(const e4_Node &nn)
{
    if (!nn.IsValid()) {
	return false;
    }
    n = nn;
    done = (!n.GetStorage(s));
    if (!done) {
	curParent = 1;
	if (n.ParentCount() < curParent) {
	    done = true;
	} else {
	    done = !n.GetParent(curParent, p);
	}
    }
    if (done) {
	n = invalidNode;
	p = invalidNode;
	s = invalidStorage;
	curParent = -1;
    }
    return true;
}

/*
 * Get the current parent.
 */

bool
e4_ParentVisitor::CurrentParent(e4_Node &pp)
{
    if (!n.IsValid() || !s.IsValid() || !p.IsValid()) {
	done = true;
	return false;
    }
    pp = p;
    return true;
}

/*
 * Get the next node.
 */

bool
e4_ParentVisitor::NextParent(e4_Node &pp)
{
    if (done) {
	return false;
    }
    Advance();
    if (done) {
	return false;
    }
    pp = p;
    return true;
}

/*
 * Advance to the next node without returning it.
 */

bool
e4_ParentVisitor::Advance()
{
    if (done) {
	return false;
    }
    curParent++;
    if (curParent > n.ParentCount()) {
	done = true;
	return false;
    }
    done = !n.GetParent(curParent, p);
    if (done) {
	return false;
    }
    return true;
}

/*
 * Get the current parent and advance to the next one.
 */

bool
e4_ParentVisitor::CurrentParentAndAdvance(e4_Node &pp)
{
    if (!CurrentParent(pp) || IsDone()) {
	return false;
    }
    (void) Advance();
    return true;
}

/*
 * Is this instance done?
 */

bool
e4_ParentVisitor::IsDone()
{
    if (done) {
	return true;
    }
    if (!s.IsValid() || !n.IsValid() || !p.IsValid()) {
	done = true;
    }
    return done;
}

/*
 * Is this instance valid?
 */

bool
e4_ParentVisitor::IsValid()
{
    if (!s.IsValid()) {
	done = true;
	return false;
    }
    return true;
}

