#include "aps.hpp"

Pos::Pos(int n) : vector<LocId>(n)
{
	reverse_iterator pi;

	for (pi = rbegin(); n; *pi++ = --n);
}

Pos::Pos(const vector<LocId> &v) : vector<LocId>(v)
{
}

Pos &Pos::add(const Pos &rhs)
{
	Pos tmp;

	if (&rhs == this) return (*this);
	swap(tmp);
	resize(tmp.size() + rhs.size());
	resize(std::set_union(tmp.begin(), tmp.end(),
			rhs.begin(), rhs.end(), begin()) - begin());
	return (*this);
}

bool Pos::includes(const Pos &rhs)
{
	return (std::includes(begin(), end(), rhs.begin(), rhs.end()));
}

Map::Map(int n) : vector<LocId>(n)
{
	reverse_iterator mi;

	for (mi = rbegin(); n; *mi++ = --n);
}

Map &Map::inverse(int n)
{
	Map tmp(n);
	const_iterator mi;
	LocId i;

	for (mi = begin(), i = 0; mi != end(); tmp[*mi++] = i++);
	swap(tmp);
	return (*this);
}

Pos Map::operator*(const Pos &rhs) const
{
	return (operator*<Pos>(rhs));
}

Map Map::operator*(const Map &rhs) const
{
	return (operator*<Map>(rhs));
}

bool Map::issymmetric(const Pos &rhs) const
{
	return (issymmetric<Pos>(rhs));
}

Map &Map::rev(int start, int len)
{
	iterator i, j;
	LocId t;

	i = begin() + start;
	j = len == -1? end(): i + len;
	while (i < j) t = *--j, *j = *i, *i++ = t;
	return (*this);
}

Map &Map::rot(int right, int start, int len)
{
	iterator i, j, k;
	int l, m, n;
	LocId t;

	i = begin() + start;
	j = len == -1? end(): i + len;
	len = j - i;
	m = right, n = len;
	while ((m %= n) && (n %= m));
	for (n += m, m = len / n; n--; *i++ = t)
		for (l = m, t = *i; --l; *i = *k, i = k)
			k = i + (right < j - i? right: right - len);
	return (*this);
}

Maps Map::nestlist(int n) const
{
	Maps maps(n+1);
	int i;

	if (!size()) return (Maps());
	maps[0] = Map(size());
	for (i = 0; i < n; i++)
		maps[i+1] = *this * maps[i];
	return (maps);
}

Poss::Poss(int n) : vector<Pos>(n)
{
}

Poss::Poss(const Pos &pos) : vector<Pos>(1, pos)
{
}

Poss &Poss::append(const Poss &poss)
{
	insert(end(), poss.begin(), poss.end());
	return (*this);
}

Maps::Maps(int n) : vector<Map>(n)
{
}

Maps::Maps(const Map &map) : vector<Map>(1, map)
{
}

Maps &Maps::append(const Maps &maps)
{
	insert(end(), maps.begin(), maps.end());
	return (*this);
}

Poss Maps::operator*(const Poss &rhs) const
{
	return (operator*<Poss>(rhs));
}

Maps Maps::operator*(const Maps &rhs) const
{
	return (operator*<Maps>(rhs));
}

Maps Maps::symmetric(const Poss &rhs) const
{
	return (symmetric<Poss>(rhs));
}

Maps Maps::close(void) const
{
	Db<Map,MapId> mapdb;
	Maps::const_iterator i;
	MapId j;
	Map map;
	Maps maps;

	if (!size()) return (Maps());
	map = Map(front().size());
	if (mapdb.isnew(map)) maps.push_back(map);
	for (j = 0; j < maps.size(); j++)
		for (i = begin(); i != end(); i++)
			if (mapdb.isnew(map = *i * maps[j]))
				maps.push_back(map);
	return (maps);
}

Shape::Shape(int an, const Poss &aposs) : n(an), poss(aposs)
{
}

std::ostream &operator<<(std::ostream &output, const Shape &shape)
{
	output << shape.n << ':' << shape.poss;
	return (output);
}

Shapes::Shapes(int n) : vector<Shape>(n)
{
}

Part::Part(ShapeId ashapeid, const Pos &apos) :
		shapeid(ashapeid), pos(apos)
{
}

bool Part::operator<(const Part &rhs) const
{
	return (shapeid < rhs.shapeid ||
			!(rhs.shapeid < shapeid || !(pos < rhs.pos)));
}

std::ostream &operator<<(std::ostream &output, const Part &part)
{
	output << part.shapeid << ':' << part.pos;
	return (output);
}

Parts::Parts(int n) : vector<Part>(n)
{
}

Parts::Parts(const Part &part) : vector<Part>(1, part)
{
}

Parts Parts::select(ShapeId shapeid) const
{
	Parts parts;
	const_iterator i;

	for (i = begin(); i != end(); i++)
		if (i->shapeid == shapeid) parts.push_back(*i);
	return (parts);
}

Parts Parts::select(const PartIds &partids) const
{
	Parts parts;
	PartIds::const_iterator pi;
	iterator p;

	parts = Parts(partids.size());
	p = parts.begin();
	for (pi = partids.begin(); pi != partids.end(); pi++)
		*p++ = (*this)[*pi];
	return (parts);
}

std::string Parts::decode(const std::string &codes,
		const std::string &src) const
{
	const_iterator ip;
	Pos::const_iterator pb, pi, pe;
	std::string dst;
	std::string::const_iterator is;

	dst = src;
	is = codes.begin();
	for (ip = begin(); ip != end(); ip++, is++) {
		pb = ip->pos.begin();
		pe = ip->pos.end();
		for (pi = pb; pi != pe; dst[*pi++] = *is);
	}
	return (dst);
}

PartIds::PartIds(int n) : vector<PartId>(n)
{
}

MapPart::MapPart(MapId amapid, PartId apartid)
	: mapid(amapid), partid(apartid)
{
}

std::ostream &operator<<(std::ostream &output, const MapPart &mappart)
{
	output << '(' << mappart.mapid << ',' << mappart.partid << ')';
	return (output);
}
