/*
 * UnboundedRegExp.h
 *
 * This file is part of Algorithms library toolkit.
 * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz)

 * Algorithms library toolkit is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * Algorithms library toolkit is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with Algorithms library toolkit.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  Created on: Nov 23, 2013
 *      Author: Jan Travnicek
 */

#pragma once

#include <common/DefaultSymbolType.h>

namespace regexp {

template < class SymbolType = DefaultSymbolType >
class UnboundedRegExp;

} /* namespace regexp */

#include <alib/string>
#include <alib/set>
#include <alib/iostream>
#include <alib/algorithm>
#include <sstream>

#include <core/components.hpp>
#include <exception/CommonException.h>

#include "UnboundedRegExpStructure.h"

#include <core/normalize.hpp>
#include <alphabet/common/SymbolNormalize.h>

#include "../formal/FormalRegExp.h"

namespace regexp {

class GeneralAlphabet;

/**
 * \brief
 * Unbounded regular expression represents regular expression. It describes regular languages. The expression consists of the following nodes:
 *   - Alternation - the representation of + in the regular expression
 *   - Concatenation - the representation of &sdot; in the regular expression
 *   - Iteration - the representation of * (Kleene star)
 *   - Epsilon - the representation of empty word
 *   - Empty - the representation of empty regular expression
 *   - Symbol - the representation of single symbol
 *
 * The unbounded representation allows nodes of concatenation and alternation to have any number of children.
 *
 * Alternation of nothing is equivalent to empty regular expression. Concatenation of nothing is equivalent to empty word.
 *
 * The structure of the regular expression is wrapped in a structure class to allow separate the alphabet from the structure for example in Extended NFA

 * \details
 * Definition is unbounded definition of regular expressions.
 * E = (T, C),
 * T (Alphabet) = finite set of terminal symbols
 * C (Content) = representation of the regular expression
 *
 * \tparam SymbolType used for the terminal alphabet
 */
template < class SymbolType >
class UnboundedRegExp final : public core::Components < UnboundedRegExp < SymbolType >, ext::set < SymbolType >, component::Set, GeneralAlphabet > {
	/**
	 * The structure of the regular expression.
	 */
	UnboundedRegExpStructure < SymbolType > m_regExp;

public:
	/**
	 * The exposed SymbolType template parameter.
	 */
	using symbol_type = SymbolType;

	/**
	 * \brief Creates a new instance of the expression. The default constructor creates expression describing empty language.
	 */
	explicit UnboundedRegExp ( );

	/**
	 * \brief Creates a new instance of the expression with a concrete alphabet and initial content.
	 *
	 * \param alphabet the initial input alphabet
	 * \param regExp the initial regexp content
	 */
	explicit UnboundedRegExp ( ext::set < SymbolType > alphabet, UnboundedRegExpStructure < SymbolType > regExp );

	/**
	 * \brief Creates a new instance of the expression based on initial content. The alphabet is derived from the content.
	 *
	 * \param regExp the initial regexp content
	 */
	explicit UnboundedRegExp ( UnboundedRegExpStructure < SymbolType > regExp );

	/**
	 * \brief Created a new instance of the expression based on the FormalRegExp representation.
	 */
	explicit UnboundedRegExp ( const FormalRegExp < SymbolType > & other );

	/**
	 * Getter of the alphabet.
	 *
	 * \returns the alphabet of the expression
	 */
	const ext::set < SymbolType > & getAlphabet ( ) const & {
		return this->template accessComponent < GeneralAlphabet > ( ).get ( );
	}

	/**
	 * Getter of the alphabet.
	 *
	 * \returns the alphabet of the expression
	 */
	ext::set < SymbolType > && getAlphabet ( ) && {
		return std::move ( this->template accessComponent < GeneralAlphabet > ( ).get ( ) );
	}

	/**
	 * Get the structure of the expression.
	 *
	 * \returns the structure of the expression.
	 */
	const UnboundedRegExpStructure < SymbolType > & getRegExp ( ) const &;

	/**
	 * Get the structure of the expression.
	 *
	 * \returns the structure of the expression.
	 */
	UnboundedRegExpStructure < SymbolType > && getRegExp ( ) &&;

	/**
	 * Set the structure of the expression.
	 *
	 * \param regExp the new structure of the expression.
	 */
	void setRegExp ( UnboundedRegExpStructure < SymbolType > param );

	/**
	 * The three way comparison implementation
	 *
	 * \param other the other instance
	 *
	 * \returns the ordering between this object and the @p other.
	 */
	auto operator <=> ( const UnboundedRegExp & other ) const {
		return std::tie ( m_regExp.getStructure ( ), getAlphabet ( ) ) <=> std::tie ( other.m_regExp.getStructure ( ), other.getAlphabet ( ) );
	}

	/**
	 * The equality comparison implementation.
	 *
	 * \param other the other object to compare with.
	 *
	 * \returns true if this and other objects are equal, false othervise
	 */
	bool operator == ( const UnboundedRegExp & other ) const {
		return std::tie ( m_regExp.getStructure ( ), getAlphabet ( ) ) == std::tie ( other.m_regExp.getStructure ( ), other.getAlphabet ( ) );
	}

	/**
	 * Print this object as raw representation to ostream.
	 *
	 * \param os ostream where to print
	 * \param instance object to print
	 *
	 * \returns modified output stream
	 */
	friend std::ostream & operator << ( std::ostream & out, const UnboundedRegExp & instance ) {
		return out << "(UnboundedRegExp " << instance.getRegExp ( ).getStructure ( ) << ")";
	}

	/**
	 * Casts this instance to as compact as possible string representation.
	 *
	 * \returns string representation of the object
	 */
	explicit operator std::string ( ) const;
};

template < class SymbolType >
UnboundedRegExp < SymbolType >::UnboundedRegExp ( ext::set < SymbolType > alphabet, UnboundedRegExpStructure < SymbolType > regExp ) : core::Components < UnboundedRegExp, ext::set < SymbolType >, component::Set, GeneralAlphabet > ( std::move ( alphabet ) ), m_regExp ( std::move ( regExp ) ) {
	if ( !this->m_regExp.getStructure ( ).checkAlphabet ( getAlphabet ( ) ) )
		throw exception::CommonException ( "Input symbols not in the alphabet." );
}

template < class SymbolType >
UnboundedRegExp < SymbolType >::UnboundedRegExp ( ) : UnboundedRegExp ( ext::set < SymbolType > ( ), UnboundedRegExpStructure < SymbolType > ( ) ) {
}

template < class SymbolType >
UnboundedRegExp < SymbolType >::UnboundedRegExp ( UnboundedRegExpStructure < SymbolType > regExp ) : UnboundedRegExp ( regExp.getStructure ( ).computeMinimalAlphabet ( ), regExp ) {
}

template < class SymbolType >
UnboundedRegExp < SymbolType >::UnboundedRegExp ( const FormalRegExp < SymbolType > & other ) : UnboundedRegExp ( other.getAlphabet ( ), UnboundedRegExpStructure < SymbolType > ( other.getRegExp ( ) ) ) {
}

template < class SymbolType >
const UnboundedRegExpStructure < SymbolType > & UnboundedRegExp < SymbolType >::getRegExp ( ) const & {
	return m_regExp;
}

template < class SymbolType >
UnboundedRegExpStructure < SymbolType > && UnboundedRegExp < SymbolType >::getRegExp ( ) && {
	return std::move ( m_regExp );
}

template < class SymbolType >
void UnboundedRegExp < SymbolType >::setRegExp ( UnboundedRegExpStructure < SymbolType > param ) {
	if ( !param.getStructure ( ).checkAlphabet ( getAlphabet ( ) ) )
		throw exception::CommonException ( "Input symbols not in the alphabet." );

	this->m_regExp = std::move ( param );
}

template < class SymbolType >
UnboundedRegExp < SymbolType >::operator std::string ( ) const {
	std::stringstream ss;
	ss << * this;
	return ss.str ( );
}

} /* namespace regexp */

namespace core {

/**
 * Helper class specifying constraints for the expression's internal alphabet component.
 *
 * \tparam SymbolType used for the terminal alphabet of the expression.
 */
template < class SymbolType >
class SetConstraint< regexp::UnboundedRegExp < SymbolType >, SymbolType, regexp::GeneralAlphabet > {
public:
	/**
	 * Returns true if the symbol is still used somewhere in the structure of the expression.
	 *
	 * \param regexp the tested expresion
	 * \param symbol the tested symbol
	 *
	 * \returns true if the symbol is used, false othervise
	 */
	static bool used ( const regexp::UnboundedRegExp < SymbolType > & regexp, const SymbolType & symbol ) {
		return regexp.getRegExp ( ).getStructure ( ).testSymbol ( symbol );
	}

	/**
	 * Returns true as all symbols are possibly available to be elements of the alphabet.
	 *
	 * \param regexp the tested expresion
	 * \param symbol the tested state
	 *
	 * \returns true
	 */
	static bool available ( const regexp::UnboundedRegExp < SymbolType > &, const SymbolType & ) {
		return true;
	}

	/**
	 * All symbols are valid as symbols of the alphabet.
	 *
	 * \param regexp the tested expresion
	 * \param symbol the tested state
	 */
	static void valid ( const regexp::UnboundedRegExp < SymbolType > &, const SymbolType & ) {
	}
};

/**
 * Helper for normalisation of types specified by templates used as internal datatypes of symbols.
 *
 * \returns new instance of the expression with default template parameters or unmodified instance if the template parameters were already the default ones
 */
template < class SymbolType >
struct normalize < regexp::UnboundedRegExp < SymbolType > > {
	static regexp::UnboundedRegExp < > eval ( regexp::UnboundedRegExp < SymbolType > && value ) {
		ext::set < DefaultSymbolType > alphabet = alphabet::SymbolNormalize::normalizeAlphabet ( std::move ( value ).getAlphabet ( ) );

		return regexp::UnboundedRegExp < > ( alphabet, std::move ( value ).getRegExp ( ).normalize ( ) );
	}
};

} /* namespace core */

extern template class regexp::UnboundedRegExp < >;

