/*
 * Alternation.cpp
 *
 *  Created on: Nov 23, 2013
 *      Author: Martin Zak
 */

#include "Alternation.h"

namespace regexp {

Alternation::Alternation() {

}

Alternation::Alternation(const Alternation& other) {
	for (const auto& element : other.elements) {
		elements.push_back(element->clone());
	}
}

Alternation::Alternation(Alternation&& other) noexcept : elements(std::move(other.elements)) {
	other.elements.clear();
}

Alternation& Alternation::operator=(const Alternation& other) {
	if (this == &other) {
		return *this;
	}

	*this = Alternation(other);

	return *this;
}

Alternation& Alternation::operator=(Alternation&& other) noexcept {
	std::swap(this->elements, other.elements);
	  
	return *this;
}

Alternation::~Alternation() noexcept {
	for (auto element : elements) {
		delete element;
	}
	elements.clear();
}

std::vector<RegExpElement*>& Alternation::getElements() {
	return elements;
}

const std::vector<RegExpElement*>& Alternation::getElements() const {
	return elements;
}

RegExpElement* Alternation::clone() const {
	return new Alternation(*this);
}

bool Alternation::operator<(const RegExpElement& other) const {
	return other > *this;
}

bool Alternation::operator==(const RegExpElement& other) const {
	return other == *this;
}

bool Alternation::operator>(const RegExpElement& other) const {
	return other < *this;
}


bool Alternation::operator<(const Concatenation&) const {
	return true;
}

bool Alternation::operator<(const Alternation& other) const {
	int thisSize = this->elements.size();
	int otherSize = other.elements.size();
	if(thisSize < otherSize) return true;
	if(thisSize > otherSize) return false;

	auto thisIter = this->elements.begin();
	auto otherIter = other.elements.begin();
	for(; thisIter != this->elements.end(); thisIter++, otherIter++) {
	  if(**thisIter != **otherIter) break;
	}
	if(thisIter == this->elements.end()) return false;

	return **thisIter < **otherIter;
}

void Alternation::getAlphabet( std::set<alphabet::Symbol> & alphabet ) const {
	for(const auto& child : this->elements)
		child->getAlphabet(alphabet);
}

bool Alternation::operator==(const Alternation& other) const {
	if(this->elements.size() != other.elements.size()) return false;

	auto thisIter = this->elements.begin();
	auto otherIter = other.elements.begin();
	for(; thisIter != this->elements.end(); thisIter++, otherIter++) {
	  if(**thisIter != **otherIter) return false;
	}

	return true;
}

void Alternation::operator>>(std::ostream& out) const {
	out << "(Alternation";
	for(const auto& e : getElements())
		out << " " << *e;

	out << ")";
}

bool Alternation::containsEmptyString() const {
	for(const auto& e : getElements())
		if(e->containsEmptyString())
			return true;

	return false; // alternation of zero regexps is empty
}

bool Alternation::isEmpty() const {
	for(const auto& e : getElements())
		if(!e->isEmpty())
			return false;

	return true; // alternation of zero regexps is empty
}

} /* namespace regexp */