/*! \file pivarianttypes.h
 * \brief Variant type
 *
 * This file declares PIVariant
*/
/*
	PIP - Platform Independent Primitives
	Variant types
	Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru

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

	This program 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 Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef PIVARIANTYPES_H
#define PIVARIANTYPES_H

#include "pistringlist.h"


class PIPropertyStorage;


namespace PIVariantTypes {

/**
 * @brief name-value pair
 */
struct PIP_EXPORT Enumerator {
	Enumerator(int v = 0, const PIString & n = PIString()): value(v), name(n) {}
	int value;
	PIString name;
};

/**
 * @brief Collection of PIVariantTypes::Enumerator. It's replace classic c-style enum.
 * Contains elements with unique name and not uniqueue values.
 */
struct PIP_EXPORT Enum {
	Enum(const PIString & n = PIString()): enum_name(n) {}

	/**
	 * @brief Find selected value.
	 * @return selected value, otherwrise 0
	 */
	int selectedValue() const;

	/**
	 * @brief Get selected name
	 * @return selected name, otherwrise empty PIString
	 */
	PIString selectedName() const {return selected;}

	/**
	 * @brief Select value if exists in Enum. If Enum contains several PIVariantTypes::Enumerator with same values,
	 * first PIVariantTypes::Enumerator will selected
	 * @param v value for selection
	 * @return true if value exists in Enum, false otherwrise
	 */
	bool selectValue(int v);

	/**
	 * @brief Select name if exists in enum
	 * @param n name for selection
	 * @return true if name exists in Enum, false otherwrise
	 */
	bool selectName(const PIString & n);

	/**
	 * @brief Find PIVariantTypes::Enumerator with specific name and return it value
	 * @param n name for search
	 * @return value of founded PIVariantTypes::Enumerator, 0 otherwrise
	 */
	int value(const PIString & n) const;

	/**
	 * @brief Find first PIVariantTypes::Enumerator with specific value and return it name
	 * @param v value for search
	 * @return name of founded PIVariantTypes::Enumerator, empty string otherwrise
	 */
	PIString name(int v) const;

	/**
	 * @brief Make vector of Enum values
	 */
	PIVector<int> values() const;

	/**
	 * @brief Make vector of Enum names
	 */
	PIStringList names() const;
	PIString enum_name;
	PIString selected;
	PIVector<Enumerator> enum_list;

	/**
	 * @brief Add PIVariantTypes::Enumerator to Enum
	 */
	Enum & operator <<(const Enumerator & v);

	/**
	 * @brief Add PIVariantTypes::Enumerator element to Enum. Element contains specific name and value more per
	 * unit then last element. If the is no elements, contains zero value.
	 * @param v name for new PIVariantTypes::Enumerator element
	 */
	Enum & operator <<(const PIString & v);

	/**
	 * @brief Add PIVariantTypes::Enumerator element for each name in vector
	 */
	Enum & operator <<(const PIStringList & v);
};

struct PIP_EXPORT File {
	File(const PIString & p = PIString(), const PIString & f = PIString(), bool abs = false, bool save_mode = false):
		file(p), filter(f), is_abs(abs), is_save(save_mode) {}
	PIString toString() const {return file;}
	PIString file;
	PIString filter;
	bool is_abs;
	bool is_save;
};

struct PIP_EXPORT Dir {
	Dir(const PIString & d = PIString(), bool abs = false):
		dir(d), is_abs(abs) {}
	PIString toString() const {return dir;}
	PIString dir;
	bool is_abs;
};

struct PIP_EXPORT Color {
	Color(uint v = 0) {rgba = v;}
	uint rgba;
};

struct PIP_EXPORT IODevice {
	IODevice();
	void set(const PIPropertyStorage & ps);
	PIPropertyStorage get() const;
	PIString toPICout() const;
	PIString prefix;
	int mode;	 // PIIODevice::DeviceMode
	int options; // PIIODevice::DeviceOptions
	PIByteArray props;
};

}

inline PIByteArray & operator <<(PIByteArray & s, const PIVariantTypes::Enumerator & v) {s << v.value << v.name; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIVariantTypes::Enumerator & v)       {s >> v.value >> v.name; return s;}
inline PICout operator <<(PICout s, const PIVariantTypes::Enumerator & v) {s << v.name << "(" << v.value << ")"; return s;}

inline PIByteArray & operator <<(PIByteArray & s, const PIVariantTypes::Enum & v) {s << v.enum_name << v.selected << v.enum_list; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIVariantTypes::Enum & v)       {s >> v.enum_name >> v.selected >> v.enum_list; return s;}
inline PICout operator <<(PICout s, const PIVariantTypes::Enum & v) {s << "Enum(" << v.selectedValue() << "=" << v.selectedName() << ")"; return s;}

inline PIByteArray & operator <<(PIByteArray & s, const PIVariantTypes::File & v) {s << v.file << v.filter << uchar((v.is_abs ? 1 : 0) + (v.is_save ? 2 : 0)); return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIVariantTypes::File & v)       {uchar f(0); s >> v.file >> v.filter >> f; v.is_abs = ((f & 1) == 1); v.is_save = ((f & 2) == 2); return s;}
inline PICout operator <<(PICout s, const PIVariantTypes::File & v) {s << "File(\"" << v.file << "\")"; return s;}

inline PIByteArray & operator <<(PIByteArray & s, const PIVariantTypes::Dir & v) {s << v.dir << v.is_abs; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIVariantTypes::Dir & v)       {s >> v.dir >> v.is_abs; return s;}
inline PICout operator <<(PICout s, const PIVariantTypes::Dir & v) {s << "Dir(\"" << v.dir << "\")"; return s;}

inline PIByteArray & operator <<(PIByteArray & s, const PIVariantTypes::Color & v) {s << v.rgba; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIVariantTypes::Color & v)       {s >> v.rgba; return s;}
inline PICout operator <<(PICout s, const PIVariantTypes::Color & v) {s.saveControl(); s << PICoutManipulators::Hex << "Color(#" << v.rgba << ")"; s.restoreControl(); return s;}

inline PIByteArray & operator <<(PIByteArray & s, const PIVariantTypes::IODevice & v) {s << v.prefix << v.mode << v.options << v.props; return s;}
inline PIByteArray & operator >>(PIByteArray & s, PIVariantTypes::IODevice & v)       {s >> v.prefix >> v.mode >> v.options >> v.props; return s;}
inline PICout operator <<(PICout s, const PIVariantTypes::IODevice & v) {s << v.toPICout(); return s;}

#endif // PIVARIANTYPES_H
