/*
** (c) 1996-2000 The Regents of the University of California (through
** E.O. Lawrence Berkeley National Laboratory), subject to approval by
** the U.S. Department of Energy.  Your use of this software is under
** license -- the license agreement is attached and included in the
** directory as license.txt or you may contact Berkeley Lab's Technology
** Transfer Department at TTD@lbl.gov.  NOTICE OF U.S. GOVERNMENT RIGHTS.
** The Software was developed under funding from the U.S. Government
** which consequently retains certain rights as follows: the
** U.S. Government has been granted for itself and others acting on its
** behalf a paid-up, nonexclusive, irrevocable, worldwide license in the
** Software to reproduce, prepare derivative works, and perform publicly
** and display publicly.  Beginning five (5) years after the date
** permission to assert copyright is obtained from the U.S. Department of
** Energy, and subject to any subsequent five (5) year renewals, the
** U.S. Government is granted for itself and others acting on its behalf
** a paid-up, nonexclusive, irrevocable, worldwide license in the
** Software to reproduce, prepare derivative works, distribute copies to
** the public, perform publicly and display publicly, and to permit
** others to do so.
*/

//
// $Id: BoxDomain.cpp,v 1.18 2001/08/06 19:40:27 car Exp $
//
#include <iostream>

#include <BoxDomain.H>

BoxDomain&
BoxDomain::intersect (const Box& b)
{
    BoxList::intersect(b);
    BL_ASSERT(ok());
    return *this;
}

void
BoxLib::intersect (BoxDomain&       dest,
		   const BoxDomain& fin,
		   const Box&       b)
{
   dest = fin;
   dest.intersect(b);
}

BoxDomain&
BoxDomain::refine (int ratio)
{
    BoxList::refine(ratio);
    BL_ASSERT(ok());
    return *this;
}

void
BoxLib::refine (BoxDomain&       dest,
		const BoxDomain& fin,
		int              ratio)
{
    dest = fin;
    dest.refine(ratio);
}

void
BoxLib::accrete (BoxDomain&       dest,
		 const BoxDomain& fin,
		 int              sz)
{
    dest = fin;
    dest.accrete(sz);
}

void
BoxLib::coarsen (BoxDomain&       dest,
		 const BoxDomain& fin,
		 int              ratio)
{
    dest = fin;
    dest.coarsen(ratio);
}

BoxDomain&
BoxDomain::complementIn (const Box&       b,
                         const BoxDomain& bl)
{
    BoxList::complementIn(b,bl);
    BL_ASSERT(ok());
    return *this;
}

BoxDomain
BoxLib::complementIn (const Box&       b,
		      const BoxDomain& bl)
{
    BoxDomain result;
    result.complementIn(b,bl);
    return result;
}

BoxList
BoxDomain::boxList () const
{
    return BoxList(*this);
}

bool
BoxDomain::operator== (const BoxDomain& rhs) const
{
    return BoxList::operator==(rhs);
}

bool
BoxDomain::operator!= (const BoxDomain& rhs) const
{
    return !BoxList::operator==(rhs);
}

BoxDomain::BoxDomain ()
    :
    BoxList(IndexType::TheCellType())
{}

BoxDomain::BoxDomain (IndexType _ctype)
    :
    BoxList(_ctype)
{}

BoxDomain::BoxDomain (const Box& bx)
    :
    BoxList(bx.ixType())
{
    add(bx);
}

void
BoxDomain::add (const Box& b)
{
    BL_ASSERT(b.ixType() == ixType());

    std::list<Box> check;
    check.push_back(b);
    for (iterator bli = lbox.begin(); bli != lbox.end(); ++bli)
    {
        std::list<Box> tmp;
        for (iterator ci = check.begin(); ci != check.end(); )
        {
            if (ci->intersects(*bli))
            {
                //
                // Remove c from the check list, compute the
                // part of it that is outside bln and collect
                // those boxes in the tmp list.
                //
                BoxList tmpbl(BoxLib::boxDiff(*ci, *bli));
                tmp.splice(tmp.end(), tmpbl.listBox());
                check.erase(ci++);
            }
            else
            {
                ++ci;
            }
        }
        check.splice(check.end(), tmp);
    }
    //
    // At this point, the only thing left in the check list
    // are boxes that nowhere intersect boxes in the domain.
    //
    lbox.splice(lbox.end(), check);
    BL_ASSERT(ok());
}

void
BoxDomain::add (const BoxList& bl)
{
    for (BoxList::const_iterator bli = bl.begin(); bli != bl.end(); ++bli)
        add(*bli);
}

BoxDomain&
BoxDomain::rmBox (const Box& b)
{
    BL_ASSERT(b.ixType() == ixType());

    std::list<Box> tmp;

    for (std::list<Box>::iterator  bli = lbox.begin(); bli != lbox.end(); )
    {
        if (bli->intersects(b))
        {
            BoxList tmpbl(BoxLib::boxDiff(*bli,b));
            tmp.splice(tmp.end(), tmpbl.listBox());
            lbox.erase(bli++);
        }
        else
        {
            ++bli;
        }
    }
    lbox.splice(lbox.end(), tmp);
    return *this;
}

bool
BoxDomain::ok () const
{
    //
    // First check to see if boxes are valid.
    //
    bool status = BoxList::ok();
    if (status)
    {
        //
        // Now check to see that boxes are disjoint.
        //
        for (const_iterator bli = begin(); bli != end(); ++bli)
        {
            const_iterator blii = bli; ++blii;
            for ( ; blii != end(); ++blii)
            {
                if (bli->intersects(*blii))
                {
                    std::cout << "Invalid DOMAIN, boxes overlap" << '\n'
                              << "b1 = " << *bli << '\n'
                              << "b2 = " << *blii << '\n';
                    status = false;
                }
            }
        }
    }
    return status;
}

BoxDomain&
BoxDomain::accrete (int sz)
{
    BoxList bl(*this);
    bl.accrete(sz);
    clear();
    add(bl);
    return *this;
}

BoxDomain&
BoxDomain::coarsen (int ratio)
{
    BoxList bl(*this);
    bl.coarsen(ratio);
    clear();
    add(bl);
    return *this;
}

std::ostream&
operator<< (std::ostream&    os,
            const BoxDomain& bd)
{
    os << "(BoxDomain " << bd.boxList() << ")" << std::flush;
    if (os.fail())
        BoxLib::Error("operator<<(ostream&,BoxDomain&) failed");
    return os;
}

