//! \~\file pipropertystorage.h
//! \~\ingroup Types
//! \~\brief
//! \~english Properties array
//! \~russian Массив свойств
/*
    PIP - Platform Independent Primitives
    Storage of properties for GUI usage
    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 PIPROPERTYSTORAGE_H
#define PIPROPERTYSTORAGE_H

#include "pivariant.h"


//! \~\ingroup Types
//! \~\brief
//! \~english This class provides key-value properties storage.
//! \~russian Этот класс предоставляет ключ-значение хранение свойств.
//! \~\details
//! \~english %PIPropertyStorage is a container for storing properties as key-value pairs with additional metadata like comments and flags.
//! \~russian %PIPropertyStorage - контейнер для хранения свойств в виде пар "ключ-значение" с дополнительными метаданными, такими как
//! комментарии и флаги.
class PIP_EXPORT PIPropertyStorage {
public:
	//! \~english Contructs an empty %PIPropertyStorage
	//! \~russian Создает пустой %PIPropertyStorage
	PIPropertyStorage() {}

	//! \~\ingroup Types
	//! \~\brief
	//! \~english PIPropertyStorage element.
	//! \~russian Элемент PIPropertyStorage.
	struct PIP_EXPORT Property {
		//! \~english Contructs %PIPropertyStorage::Property with name "n", comment "c", value "v" and flags "f"
		//! \~russian Создает %PIPropertyStorage::Property с именем "n", комментарием "c", значением "v" и флагами "f"
		Property(const PIString & n = PIString(), const PIString & c = PIString(), const PIVariant & v = PIVariant(), int f = 0)
			: name(n)
			, comment(c)
			, value(v)
			, flags(f) {}

		//! \~english Contructs copy of another %PIPropertyStorage::Property "o"
		//! \~russian Создает копию %PIPropertyStorage::Property "o"
		Property(const Property & o): name(o.name), comment(o.comment), value(o.value), flags(o.flags) {}

		Property(Property && o) { swap(o); }

		//! \~english Assign operator
		//! \~russian Оператор присваивания
		Property & operator=(const Property & v) {
			name    = v.name;
			comment = v.comment;
			value   = v.value;
			flags   = v.flags;
			return *this;
		}
		Property & operator=(Property && v) {
			swap(v);
			return *this;
		}


		//! \~english Returns value as boolean
		//! \~russian Возвращает значение как логическое
		bool toBool() const { return value.toBool(); }

		//! \~english Returns value as integer
		//! \~russian Возвращает значение как целое
		int toInt() const { return value.toInt(); }

		//! \~english Returns value as float
		//! \~russian Возвращает значение как float
		float toFloat() const { return value.toFloat(); }

		//! \~english Returns value as double
		//! \~russian Возвращает значение как double
		double toDouble() const { return value.toDouble(); }

		//! \~english Returns value as string
		//! \~russian Возвращает значение как строку
		PIString toString() const { return value.toString(); }

		void swap(Property & o) {
			name.swap(o.name);
			comment.swap(o.comment);
			value.swap(o.value);
			piSwap(flags, o.flags);
		}

		//! \~english Property name (uniqueue for %PIPropertyStorage)
		//! \~russian Имя свойства (уникальное для %PIPropertyStorage)
		//! \~\details
		//! \~english Unique identifier for the property within a %PIPropertyStorage instance.
		//! \~russian Уникальный идентификатор свойства в экземпляре %PIPropertyStorage.
		PIString name;

		//! \~english Optional description of property
		//! \~russian Опциональный комментарий свойства
		//! \~\details
		//! \~english Additional descriptive text providing information about the property's purpose or usage.
		//! \~russian Дополнительный описывающий текст, предоставляющий информацию о назначении или использовании свойства.
		PIString comment;

		//! \~english Property value
		//! \~russian Значение свойства
		//! \~\details
		//! \~english The value stored in the property, which can be of any type supported by %PIVariant.
		//! \~russian Значение, хранящееся в свойстве, которое может быть любого типа, поддерживаемого %PIVariant.
		PIVariant value;

		//! \~english Abstract flags which may be used for user needs
		//! \~russian Абстрактные флаги, могут быть использованы для своих нужд
		//! \~\details
		//! \~english User-defined flags for application-specific property management.
		//! \~russian Флаги, определяемые пользователем, для управления свойствами, специфичными для приложения.
		int flags;
	};

	//! \~english Contructs %PIPropertyStorage with "pl" properties
	//! \~russian Создает %PIPropertyStorage со свойствами "pl"
	PIPropertyStorage(const PIVector<Property> & pl) { props = pl; }

	//! \~english Contructs %PIPropertyStorage from another "o"
	//! \~russian Создает %PIPropertyStorage из другого "o"
	PIPropertyStorage(PIVector<Property> && o): props(std::move(o)) {}

	typedef PIVector<Property>::const_iterator const_iterator;
	typedef PIVector<Property>::iterator iterator;
	typedef Property value_type;

	iterator begin() { return props.begin(); }
	const_iterator begin() const { return props.begin(); }
	iterator end() { return props.end(); }
	const_iterator end() const { return props.end(); }

	//! \~english Returns properties count
	//! \~russian Возвращает количество свойств
	int length() const { return props.length(); }

	//! \~english Returns properties count
	//! \~russian Возвращает количество свойств
	int size() const { return props.size(); }

	//! \~english Returns if no properties
	//! \~russian Возвращает нет ли свойств
	bool isEmpty() const { return props.isEmpty(); }

	//! \~english Returns if properties
	//! \~russian Возвращает есть ли свойства
	bool isNotEmpty() const { return props.isNotEmpty(); }

	//! \~english Returns first property
	//! \~russian Возвращает первое свойство
	Property & front() { return props.front(); }

	//! \~english Returns first property as const
	//! \~russian Возвращает первое свойство как константу
	const Property & front() const { return props.front(); }

	//! \~english Returns last property
	//! \~russian Возвращает последнее свойство
	Property & back() { return props.back(); }

	//! \~english Returns last property as const
	//! \~russian Возвращает последнее свойство как константу
	const Property & back() const { return props.back(); }

	//! \~english Remove property at index "i"
	//! \~russian Удаляет свойство по индексу "i"
	void removeAt(int i) { props.remove(i); }

	//! \~english Remove all properties
	//! \~russian Удаляет все свойства
	void clear() { props.clear(); }


	//! \~english Returns copy of this %PIPropertyStorage
	//! \~russian Возвращает копию этого %PIPropertyStorage
	PIPropertyStorage copy() const { return PIPropertyStorage(*this); }

	//! \~english Returns properties count
	//! \~russian Возвращает количество свойств
	int propertiesCount() const { return props.size(); }

	//! \~english Returns properties as PIVector
	//! \~russian Возвращает свойства как PIVector
	PIVector<Property> & properties() { return props; }

	//! \~english Returns properties as const PIVector
	//! \~russian Возвращает свойства как константный PIVector
	const PIVector<Property> & properties() const { return props; }

	const PIPropertyStorage & propertyStorage() const { return *this; }

	//! \~english Returns if properties with name "name" exists
	//! \~russian Возвращает присутствует ли свойство с именем "name"
	bool isPropertyExists(const PIString & name) const;

	//! \~english Remove all properties
	//! \~russian Удаляет все свойства
	void clearProperties() { props.clear(); }

	//! \~english Add property if name isn't present in storage, otherwrise update existing property with same name
	//! \~russian Добавляет новое свойство, если его имени не было в контейнере, иначе обновляет существующее свойство с этим именем
	bool addProperty(const Property & p);
	bool addProperty(Property && p);

	//! \~english Add property if name isn't present in storage, otherwrise update existing property with same name
	//! \~russian Добавляет новое свойство, если его имени не было в контейнере, иначе обновляет существующее свойство с этим именем
	bool addProperty(const PIString & _name, const PIVariant & _def_value, const PIString & _comment = PIString(), int _flags = 0);

	//! \~english Remove property with name "name", returns if property removed
	//! \~russian Удаляет свойство с именем "name", возвращает было ли оно удалено
	bool removeProperty(const PIString & name);

	//! \~english Remove all properties with flag "flag" set, returns removed properties count
	//! \~russian Удаляет все свойства с флагом "flag", возвращает количество удаленных свойств
	int removePropertiesByFlag(int flag);

	//! \~english Merge other "properties" into this
	//! \~russian Объединяет "properties" с текущим контейнером
	//! \~\details
	//! \~english Merges the specified properties vector into this container, updating existing properties and adding new ones.
	//! \~russian Объединяет указанный вектор свойств с текущим контейнером, обновляя существующие свойства и добавляя новые.
	void updateProperties(const PIVector<Property> & properties, int flag_ignore = 0);

	//! \~english Returns property with name "name" or default-constructed %PIPropertyStorage::Property
	//! \~russian Возвращает свойство с именем "name" или пустое %PIPropertyStorage::Property
	Property propertyByName(const PIString & name) const;

	//! \~english Returns property value with name "name" or invalid %PIVariant
	//! \~russian Возвращает значение свойства с именем "name" или недействительный %PIVariant
	PIVariant propertyValueByName(const PIString & name) const;

	//! \~english Set value of property with name "name" to "value", returns if property exists
	//! \~russian Устанавливает значение "value" свойству с именем "name", возвращает существует ли такое свойство
	bool setPropertyValue(const PIString & name, const PIVariant & value);

	//! \~english Set comment of property with name "name" to "comment", returns if property exists
	//! \~russian Устанавливает комментарий "comment" свойству с именем "name", возвращает существует ли такое свойство
	bool setPropertyComment(const PIString & name, const PIString & comment);

	//! \~english Set flags of property with name "name" to "flags", returns if property exists
	//! \~russian Устанавливает флаги "flags" свойству с именем "name", возвращает существует ли такое свойство
	bool setPropertyFlags(const PIString & name, int flags);

	//! \~english Add property "p"
	//! \~russian Добавляет свойство "p"
	PIPropertyStorage & operator<<(const PIPropertyStorage::Property & p) {
		props << p;
		return *this;
	}

	//! \~english Add properties "p"
	//! \~russian Добавляет свойства "p"
	PIPropertyStorage & operator<<(const PIVector<Property> & p) {
		props << p;
		return *this;
	}

	//! \~english Add properties "p"
	//! \~russian Добавляет свойства "p"
	//! \~\details
	//! \~english Appends multiple properties from another %PIPropertyStorage to this container using the << operator.
	//! \~russian Добавляет несколько свойств из другого %PIPropertyStorage в этот контейнер с использованием оператора <<.
	PIPropertyStorage & operator<<(const PIPropertyStorage & p) {
		props << p.props;
		return *this;
	}

	//! \~english Returns property with index "i"
	//! \~russian Возвращает свойство по индексу "i"
	Property & operator[](int i) { return props[i]; }

	//! \~english Returns property with index "i" as const
	//! \~russian Возвращает свойство по индексу "i" как константу
	const Property & operator[](int i) const { return props[i]; }

	//! \~english Returns property with name "name"
	//! \~russian Возвращает свойство с именем "name"
	Property & operator[](const PIString & name);

	//! \~english Returns property with name "name" as const
	//! \~russian Возвращает свойство с именем "name" как константу
	const Property operator[](const PIString & name) const;

protected:
	PIVector<Property> props;
};


//! \relatesalso PIBinaryStream
//! \~english Store operator.
//! \~russian Оператор сохранения.
BINARY_STREAM_WRITE(PIPropertyStorage::Property) {
	s << v.name << v.value << v.comment << v.flags;
	return s;
}

//! \relatesalso PIBinaryStream
//! \~english Restore operator.
//! \~russian Оператор извлечения.
BINARY_STREAM_READ(PIPropertyStorage::Property) {
	s >> v.name >> v.value >> v.comment >> v.flags;
	return s;
}


//! \relatesalso PIBinaryStream
//! \~english Store operator.
//! \~russian Оператор сохранения.
BINARY_STREAM_WRITE(PIPropertyStorage) {
	s << v.properties();
	return s;
}

//! \relatesalso PIBinaryStream
//! \~english Restore operator.
//! \~russian Оператор извлечения.
BINARY_STREAM_READ(PIPropertyStorage) {
	s >> v.properties();
	return s;
}


#endif // PIPROPERTYSTORAGE_H
