/*! \file piconstchars.h
 * \ingroup Text
 * \brief
 * \~english C-String class
 * \~russian Класс C-строки
 */
/*
    PIP - Platform Independent Primitives
    C-String class
    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 PICONSTCHARS_H
#define PICONSTCHARS_H

#include "picout.h"


//! \~\ingroup Text
//! \~\brief
//! \~english C-String class.
//! \~russian Класс C-строки.
class PIP_EXPORT PIConstChars {
public:
	//! \~english Constructs an null string.
	//! \~russian Создает нулевую строку.
	PIConstChars() {}

	//! \~english Constructs string from C-string "string".
	//! \~russian Создает строку из C-строки "string".
	PIConstChars(const char * string) {
		str = string;
		len = strlen(string);
	}

	//! \~english Constructs string from "size" characters of buffer "data".
	//! \~russian Создает строку из "size" символов массива "data".
	PIConstChars(const char * data, size_t size) {
		str = data;
		len = size;
	}

	//! \~english Constructs a copy of string.
	//! \~russian Создает копию строки.
	PIConstChars(const PIConstChars & o) {
		str = o.str;
		len = o.len;
	}


	//! \~english Read-only access to character by `index`.
	//! \~russian Доступ на чтение к символу по индексу `index`.
	inline char operator[](size_t index) const { return str[index]; }

	//! \~english Read-only access to character by `index`.
	//! \~russian Доступ на чтение к символу по индексу `index`.
	inline char at(size_t index) const { return str[index]; }

	//! \~english Returns \c char * string pointer.
	//! \~russian Возвращает \c char * указатель строки.
	inline const char * data() const { return str; }

	//! \~english Returns \c true if string doesn`t have any data.
	//! \~russian Возвращает \c true если строка не имеет данных.
	inline bool isNull() const { return !str; }

	//! \~english Returns \c true if string is empty, i.e. length = 0, or null.
	//! \~russian Возвращает \c true если строка пустая, т.е. длина = 0, или нулевая.
	inline bool isEmpty() const { return len == 0; }

	//! \~english Returns \c true if string is not empty, i.e. length > 0.
	//! \~russian Возвращает \c true если строка непустая, т.е. длина > 0.
	inline bool isNotEmpty() const { return len > 0; }

	//! \~english Returns \c true if string contains character "c".
	//! \~russian Возвращает \c true если строка содержит символ "c".
	bool contains(char c) const;

	//! \~english Returns characters length of string.
	//! \~russian Возвращает длину строки в символах.
	inline size_t length() const { return len; }

	//! \~english Returns characters length of string.
	//! \~russian Возвращает длину строки в символах.
	inline size_t size() const { return len; }

	//! \~english Returns characters length of string.
	//! \~russian Возвращает длину строки в символах.
	inline ssize_t size_s() const { return len; }

	//! \~english Returns if string starts with "str".
	//! \~russian Возвращает начинается ли строка со "str".
	bool startsWith(const PIConstChars & str) const;

	//! \~english Returns if string starts with "c".
	//! \~russian Возвращает начинается ли строка с "c".
	bool startsWith(const char c) const;

	//! \~english Returns if string ends with "str".
	//! \~russian Возвращает оканчивается ли строка на "str".
	bool endsWith(const PIConstChars & str) const;

	//! \~english Returns if string ends with "c".
	//! \~russian Возвращает оканчивается ли строка "c".
	bool endsWith(const char c) const;

	//! \~english Returns part of string from character at index "start" and maximum length "len".
	//! \~russian Возвращает подстроку от символа "start" и максимальной длиной "len".
	//! \~\sa \a left(), \a right()
	PIConstChars mid(const int start, const int len = -1) const;

	//! \~english Returns part of string from start and maximum length "len".
	//! \~russian Возвращает подстроку от начала и максимальной длиной "len".
	//! \~\sa \a mid(), \a right()
	PIConstChars left(const int len) const;

	//! \~english Returns part of string at end and maximum length "len".
	//! \~russian Возвращает подстроку максимальной длиной "len" и до конца.
	//! \~\sa \a mid(), \a left()
	PIConstChars right(const int len) const;

	//! \~english Remove part of string from start and maximum length "len" and return this string.
	//! \~russian Удаляет часть строки от начала и максимальной длины "len", возвращает эту строку.
	//! \~\sa \a cutRight()
	PIConstChars & cutLeft(const int len);

	//! \~english Remove part of string at end and maximum length "len" and return this string.
	//! \~russian Удаляет часть строки максимальной длины "len" от конца, возвращает эту строку.
	//! \~\sa \a cutLeft()
	PIConstChars & cutRight(const int len);

	//! \~english Take a part from the begin of string with maximum length "len" and return it.
	//! \~russian Извлекает часть строки от начала максимальной длины "len" и возвращает её.
	//! \~\sa \a takeRight()
	PIConstChars takeLeft(const int len);

	//! \~english Take a part from the end of string with maximum length "len" and return it.
	//! \~russian Извлекает часть строки с конца максимальной длины "len" и возвращает её.
	//! \~\sa \a takeLeft()
	PIConstChars takeRight(const int len);

	//! \~english Remove spaces at the start and at the end of string and return this string.
	//! \~russian Удаляет пробельные символы с начала и конца строки и возвращает эту строку.
	//! \~\sa \a trimmed()
	PIConstChars & trim();

	//! \~english Returns copy of this string without spaces at the start and at the end.
	//! \~russian Возвращает копию этой строки без пробельных символов с начала и конца.
	//! \~\sa \a trim()
	PIConstChars trimmed() const { return PIConstChars(*this).trim(); }

	//! \~english Returns as PIString.
	//! \~russian Возвращает как PIString.
	PIString toString() const;

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	inline PIConstChars & operator=(const PIConstChars & s) {
		if (this == &s) return *this;
		len = s.len;
		str = s.str;
		return *this;
	}

	//! \~english Assign move operator.
	//! \~russian Оператор перемещающего присваивания.
	inline PIConstChars & operator=(PIConstChars && s) {
		swap(s);
		return *this;
	}

	//! \~english Assign operator.
	//! \~russian Оператор присваивания.
	inline PIConstChars & operator=(const char * s) {
		str = s;
		len = strlen(s);
		return *this;
	}

	//! \~english Compare operator.
	//! \~russian Оператор сравнения.
	inline bool operator==(const PIConstChars & s) const {
		if (isNull() && s.isNull()) return true;
		if (isNull() xor s.isNull()) return false;
		if (size() != s.size()) return false;
		return strncmp(str, s.str, size()) == 0;
	}

	//! \~english Compare operator.
	//! \~russian Оператор сравнения.
	inline bool operator!=(const PIConstChars & s) const { return !(*this == s); }

	//! \~english Compare operator.
	//! \~russian Оператор сравнения.
	inline bool operator<(const PIConstChars & s) const {
		if (isNull() && s.isNull()) return false;
		if (isNull() && !s.isNull()) return true;
		if (!isNull() && s.isNull()) return false;
		if (size() == s.size()) return strncmp(str, s.str, size()) < 0;
		return size() < s.size();
	}

	//! \~english Compare operator.
	//! \~russian Оператор сравнения.
	inline bool operator>(const PIConstChars & s) const {
		if (isNull() && s.isNull()) return false;
		if (isNull() && !s.isNull()) return false;
		if (!isNull() && s.isNull()) return true;
		if (size() == s.size()) return strncmp(str, s.str, size()) > 0;
		return size() > s.size();
	}

	//! \~english Returns hash of string content.
	//! \~russian Возвращает хэш содержимого строки.
	inline uint hash() const {
		if (isEmpty()) return 0;
		return piHashData((const uchar *)str, len);
	}

	inline void swap(PIConstChars & v) {
		piSwap<const char *>(str, v.str);
		piSwap<size_t>(len, v.len);
	}

private:
	const char * str = nullptr;
	size_t len       = 0;
};


//! \relatesalso PICout
//! \~english Output operator to \a PICout.
//! \~russian Оператор вывода в \a PICout.
inline PICout operator<<(PICout s, const PIConstChars & v) {
	s.space();
	if (v.isNull())
		s.write("(null)");
	else {
		s.quote();
		s.write(v.data(), v.size());
		s.quote();
	}
	return s;
}


template<>
inline uint piHash(const PIConstChars & s) {
	return s.hash();
}


#endif // PICONSTCHARS_H
