/*
    PIP - Platform Independent Primitives
    File
    Copyright (C) 2014  Ivan Pelipenko peri4ko@gmail.com

    This program 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.

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

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

#include "pifile.h"


/*! \class PIFile
 * \brief Local file
 * 
 * \section  PIFile_sec0 Synopsis
 * This class provide access to local file. You can manipulate
 * binary content or use this class as text stream. To binary
 * access there are function \a read(), \a write(), and many
 * \a writeBinary() functions. For write variables to file in
 * their text representation threr are many "<<" operators.
 * 
 * \section  PIFile_sec1 Position
 * Each opened file has a read/write position - logical position
 * in the file content you read from or you write to. You can
 * find out current position with function \a pos(). Function
 * \a seek(llong position) move position to position "position",
 * \a seekToBegin() move position to the begin of file,
 * \a seekToEnd() move position to the end of file.
 * 
 */

REGISTER_DEVICE(PIFile);


bool PIFile::openDevice() {
	close();
	if (path().isEmpty()) return false;
	//piCout << "fopen " << path_.data() << ": " << strType(mode_).data() << fd;
	fd = fopen(path().data(), strType(mode_).data());
	opened_ = (fd != 0);
#ifndef WINDOWS
	if (opened_) fcntl(fileno(fd), F_SETFL, O_NONBLOCK);
#endif
	seekToBegin();
	//piCout << "open file" << fd << opened_;
	return opened_;
}


bool PIFile::closeDevice() {
	//piCout << "close file" << fd << opened_;
	if (!opened_ || fd == 0) return true;
	bool cs = (fclose(fd) == 0);
	if (cs) fd = 0;
	//piCout << "closed file" << fd << opened_;
	return cs;
}


PIString PIFile::readLine() {
	PIString str;
	if (!opened_) return str;
	int cc, cp = 0;
	while (!isEnd() && cp < 4095) {
		cc = fgetc(fd);
		if (char(cc) == '\n' || cc == EOF) break;
		str.push_back(char(cc));
	}
	//cout << "readline: " << str << endl;
	return str;
}


llong PIFile::readAll(void * data) {
	llong cp = pos(), s = size(), i = -1;
	seekToBegin();
	if (s < 0) {
		while (!isEnd())
			read(&(((char*)data)[++i]), 1);
	} else
		read((char * )data, s);
	seek(cp);
	return s;
}


PIByteArray PIFile::readAll(bool forceRead) {
	PIByteArray a;
	llong cp = pos();
	if (forceRead) {
		seekToBegin();
		while (!isEnd())
			a.push_back(readChar());
		seek(cp);
		return a;
	}
	llong s = size();
	if (s < 0) return a;
	a.resize(s);
	s = readAll(a.data());
	seek(cp);
	if (s >= 0) a.resize(s);
	return a;
}


llong PIFile::size() {
	if (!opened_) return -1;
	llong s, cp = pos();
	seekToEnd();
	s = pos();
	seek(cp);
	return s;
}


void PIFile::resize(llong new_size, uchar fill_) {
	llong ds = new_size - size();
	if (ds == 0) return;
	if (ds > 0) {
		uchar * buff = new uchar[ds];
		memset(buff, fill_, ds);
		write(buff, ds);
		delete[] buff;
		return;
	}
	piCoutObj << "Downsize is not support yet :-(";
}



bool PIFile::isExists(const PIString & path) {
	FILE * f = fopen(PIString(path).data(), "r");
	bool ok = (f != 0);
	if (ok) fclose(f);
	return ok;
}


PIString PIFile::constructFullPath() const {
	return fullPathPrefix() + "://" + path();
}


void PIFile::configureFromFullPath(const PIString & full_path) {
	setPath(full_path);
}
