/*
    PIP - Platform Independent Primitives
    PIIODevice wrapper around PIString
    Ivan Pelipenko peri4ko@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/>.
*/

#include "piiostring.h"

#include "pitranslator.h"


//! \class PIIOString piiostring.h
//! \details
//! \~english
//! This class allow you to use PIString as PIIODevice, e.g. to pass it to PIConfig.
//!
//! \~russian
//! Этот класс позволяет использовать PIString в качестве PIIODevice, например,
//! для передачи в PIConfig.
//!


PIIOString::PIIOString(PIString * string, PIIODevice::DeviceMode mode) {
	open(string, mode);
}


PIIOString::PIIOString(const PIString & string) {
	open(string);
}


void PIIOString::clear() {
	if (str) str->clear();
	pos = 0;
}


bool PIIOString::open(PIString * string, PIIODevice::DeviceMode mode) {
	if (mode == PIIODevice::ReadWrite) {
		piCoutObj << "Error: ReadWrite mode not supported, use WriteOnly or ReadOnly"_tr("PIIOString");
		str = nullptr;
		return false;
	}
	str = string;
	return PIIODevice::open(mode);
}


bool PIIOString::open(const PIString & string) {
	str = const_cast<PIString *>(&string);
	return PIIODevice::open(PIIODevice::ReadOnly);
}


bool PIIOString::isEnd() const {
	if (!str) return true;
	if (mode_ == PIIODevice::WriteOnly)
		return pos >= str->size_s();
	else {
		str->dataUTF8();
		return pos >= static_cast<ssize_t>(str->lastDataSize());
	}
}


void PIIOString::seekToBegin() {
	if (!str) return;
	pos = 0;
}


void PIIOString::seekToEnd() {
	if (!str) return;
	if (mode_ == PIIODevice::WriteOnly)
		pos = str->size_s();
	else {
		str->dataUTF8();
		pos = str->lastDataSize();
	}
}


PIString PIIOString::readLine() {
	if (!canRead() || !str) return PIString();
	auto utf8_data    = str->dataUTF8();
	ssize_t utf8_size = str->lastDataSize();
	int pp            = pos;
	while (++pp < utf8_size) {
		if (utf8_data[pp] == '\n') break;
	}
	PIString ret = PIString::fromUTF8(&(utf8_data[pos]), pp - pos);
	pos          = piMini(pp + 1, utf8_size);
	return ret;
}


ssize_t PIIOString::readDevice(void * read_to, ssize_t max_size) {
	if (!canRead() || !str || max_size <= 0) return -1;
	auto utf8_data    = str->dataUTF8();
	ssize_t utf8_size = str->lastDataSize();
	if (pos >= utf8_size) return 0;
	int ret = piMini(max_size, utf8_size - pos);
	if (ret <= 0) return 0;
	memcpy(read_to, &(utf8_data[pos]), ret);
	pos += ret;
	return ret;
}


ssize_t PIIOString::writeDevice(const void * data, ssize_t max_size) {
	if (!canWrite() || !str) return -1;
	// piCout << "write" << data;
	if (pos > str->size_s()) pos = str->size_s();
	PIString rs = PIString::fromUTF8((const char *)data, max_size);
	if (rs.size_s() > max_size) rs.resize(max_size);
	str->insert(pos, rs);
	pos += rs.size_s();
	return strlen((const char *)data);
}


int PIIOString::writeString(const PIString & string) {
	if (!canWrite() || !str) return -1;
	if (pos > str->size_s()) pos = str->size_s();
	str->insert(pos, string);
	pos += string.size_s();
	return string.size_s();
}


ssize_t PIIOString::bytesAvailable() const {
	if (!str) return 0;
	return str->size() - pos;
}


bool PIIOString::openDevice() {
	pos = 0;
	return (str != 0);
}
