//=============================================================================
//
//   File : kvi_fileutils.cpp
//   Creation date : Fri Dec 25 1998 18:26:48 by Szymon Stefanek
//
//   This file is part of the KVirc irc client distribution
//   Copyright (C) 1998-2007 Szymon Stefanek (pragma at kvirc dot net)
//
//   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 2
//   of the License, or (at your opinion) 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, write to the Free Software Foundation,
//   Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
//=============================================================================

#define __KVILIB__


#define _KVI_FILEUTLIS_CPP_
#include "kvi_fileutils.h"
#include "kvi_qstring.h"
#include "kvi_file.h"
#include "kvi_malloc.h"

#include <tqdir.h>
#include <tqfileinfo.h>
#include <tqglobal.h>
#include <tqtextcodec.h>
#include <tqtextstream.h>


namespace KviFileUtils
{
	/*
		WORKING CODE BUT UNUSED FOR NOW
	bool readLine(TQFile * f,TQString &szBuffer,bool bClearBuffer)
	{
		// FIXME: Should this assume UTF8 encoding ?
		char tmp_buf[256];
		int cur_len = 0;
		//char *cur_ptr = tmp_buf;
		if(bClearBuffer)szBuffer = "";
		int ch = f->getch();
	
		while((ch != -1)&&(ch != '\n')&&(ch != 0))
		{
			tmp_buf[cur_len] = ch;
			cur_len++;
			if(cur_len > 255)
			{
				if(tmp_buf[255] == '\r')cur_len--; //Ignore CR...
				int lastlen = szBuffer.length();
				szBuffer.setLength(lastlen + cur_len);
				TQChar *p1 = szBuffer.unicode() + lastlen;
				char * p2 = tmp_buf;
				for(int i=0;i<cur_len;i++)*p1++ = *p2++;
				cur_len = 0;
			}
			ch = f->getch();
		}
		if(ch == 0)
		{
			tqDebug("Warning : %s is not an ascii file",f->name().latin1());
		}
		if(cur_len > 0)
		{
			if(tmp_buf[cur_len - 1] == '\r')cur_len--; //Ignore CR...
			int lastlen = szBuffer.length();
			szBuffer.setLength(lastlen + cur_len);
			TQChar *p1 = szBuffer.unicode() + lastlen;
			char * p2 = tmp_buf;
			for(int i=0;i<cur_len;i++)*p1++ = *p2++;
		}
		return (ch == '\n'); //more data to read else a broken file or EOF
	}

	bool loadFileStripCR(const TQString &szPath,TQString &szBuffer)
	{
		TQFile f(szPath);
		if(!f.open(IO_ReadOnly))return false;
		szBuffer = "";
		while(readLine(&f,szBuffer,false))
		{
			szBuffer.append('\n'); // readLine returned true...last char was a newline
		}
		// readLine returned false , no ending newline encountered
		return true;
	}
	*/

	bool makeDir(const TQString &szPath)
	{
		TQDir d;
		TQString dir = KviTQString::trimmed(szPath);
		adjustFilePath(dir);
		TQString createdDir;

#ifdef COMPILE_ON_WINDOWS
		int idx = dir.find(':');
		if(idx == 1)
		{
			createdDir = dir.left(2);
			dir.remove(0,2);
		}
#endif

		KviTQString::stripLeft(dir,KVI_PATH_SEPARATOR_CHAR);
		while(!dir.isEmpty())
		{
			createdDir += KVI_PATH_SEPARATOR;
			createdDir += KviTQString::getToken(dir,KVI_PATH_SEPARATOR_CHAR);
			if(!directoryExists(createdDir))
			{
				if(!d.mkdir(createdDir))
				{
					tqDebug("Can't create directory %s",createdDir.local8Bit().data());
					return false;
				}
			}
			KviTQString::stripLeft(dir,KVI_PATH_SEPARATOR_CHAR);
		}
		return true;
	}
	
	bool makeDir(const char* path)
	{
		TQString szPath=TQString::fromUtf8(path);
		return makeDir(szPath);
	}

	bool renameFile(const TQString &szSrc,const TQString &szDst)
	{
		TQDir d;
		return d.rename(szSrc,szDst);
	}

	bool renameFile(const char* path,const char* path2)
	{
		TQString szPath=TQString::fromUtf8(path);
		TQString szPath2=TQString::fromUtf8(path2);
		return renameFile(szPath,szPath2);
	}

	bool copyFile(const TQString &szSrc,const TQString &szDst)
	{
		KviFile f1(szSrc);
		if(!f1.openForReading())return false;
		KviFile f2(szDst);
		if(!f2.openForWriting())
		{
			f1.close();
			return false;
		}
		char buffer[1024];
		while(!f1.atEnd())
		{
			int len = f1.readBlock(buffer,1024);
			if(len <= 0)
			{
				f1.close();
				f2.close();
				return false; //"serious error"
			}
			f2.writeBlock(buffer,len);
		}
		f1.close();
		f2.close();
		return true;
	}

	bool copyFile(const char* path,const char* path2)
	{
		TQString szPath=TQString::fromUtf8(path);
		TQString szPath2=TQString::fromUtf8(path2);
		return copyFile(szPath,szPath2);
	}

	bool loadFile(const TQString &szPath,TQString &szBuffer,bool bUtf8)
	{
		KviFile f(szPath);
		if(!f.openForReading())return false;
		if(bUtf8)
		{
			TQByteArray ba = f.readAll();
			szBuffer = TQString::fromUtf8(ba.data(),ba.size());
			//tqDebug("BUFFERLEN: %d",szBuffer.length());
		} else {
			szBuffer = TQString(f.readAll());
		}
		return true;
	}
	
	bool loadFile(const char* path,TQString &szBuffer,bool bUtf8)
	{
		TQString szPath=TQString::fromUtf8(path);
		return loadFile(szPath,szBuffer,bUtf8);
	}	
	
	void adjustFilePath(TQString &szPath)
	{
#ifdef COMPILE_ON_WINDOWS
		szPath.replace('/',"\\");
		while(szPath.find("\\\\") != -1)szPath.replace("\\\\","\\");
		// FIXME: Use the default drive here ?
		if(szPath.startsWith("\\"))szPath.prepend("C:");
#else
		szPath.replace('\\',"/");
		while(KviTQString::find(szPath,"//") != -1)szPath.replace("//","/");
		// deal with windows paths
		if((szPath.length() > 2) && (szPath.at(0) != TQChar('/')))
		{
			if((szPath.at(1) == TQChar(':')) && (szPath.at(2) == TQChar('/')))
			{
				szPath.remove(0,2);
			}
		}
		szPath=TQDir::cleanDirPath(szPath);
#endif
		
	}
	
	bool directoryExists(const TQString &szPath)
	{
		TQFileInfo f(szPath);
		return (f.exists() && f.isDir());
	}

	bool directoryExists(const char* path)
	{	
		TQString szPath=TQString::fromUtf8(path);
		TQFileInfo f(szPath);
		return (f.exists() && f.isDir());
	}

	bool fileExists(const TQString &szPath)
	{
		TQFileInfo f(szPath);
		return (f.exists() && f.isFile());
	}
	
	bool fileExists(const char* path)
	{	
		TQString szPath=TQString::fromUtf8(path);
		return fileExists(szPath);
	}
	
	bool removeFile(const TQString &szPath)
	{
		TQDir d;
		return d.remove(szPath);
	}

	bool removeFile(const char* path)
	{
		TQString szPath=TQString::fromUtf8(path);
		return removeFile(szPath);
	}

	bool removeDir(const TQString &szPath)
	{
		TQDir d;
		return d.rmdir(szPath);
	}
	
	bool removeDir(const char* path)
	{
		TQString szPath=TQString::fromUtf8(path);
		return removeDir(szPath);
	}

	bool deleteDir(const TQString &szPath)
	{
		TQDir d(szPath);
		TQStringList sl = d.entryList(TQDir::Dirs);
		TQStringList::Iterator it;
		for(it=sl.begin();it != sl.end();it++)
		{
			TQString szSubdir = *it;
			if(!(KviTQString::equalCS(szSubdir,"..") || KviTQString::equalCS(szSubdir,".")))
			{
				TQString szSubPath = szPath;
				KviTQString::ensureLastCharIs(szSubPath,TQChar(KVI_PATH_SEPARATOR_CHAR));
				szSubPath += szSubdir;
				if(!KviFileUtils::deleteDir(szSubPath))
					return false;
			}
		}

		sl = d.entryList(TQDir::Files);
		for(it=sl.begin();it != sl.end();it++)
		{
			TQString szFilePath = szPath;
			KviTQString::ensureLastCharIs(szFilePath,TQChar(KVI_PATH_SEPARATOR_CHAR));
			szFilePath += *it;
			if(!KviFileUtils::removeFile(szFilePath))
				return false;
		}

		return KviFileUtils::removeDir(szPath);
	}
	
	bool writeFile(const TQString &szPath,const TQString &szData,bool bAppend)
	{
		KviFile f(szPath);
		if(!f.openForWriting(bAppend))return false;
		KviTQCString szTmp = KviTQString::toUtf8(szData);
		if(!szTmp.data())return true;
		if(f.writeBlock(szTmp.data(),szTmp.length()) != ((int)(szTmp.length())))return false;
		return true;
	}

	bool writeFile(const char* path,const TQString &szData,bool bAppend)
	{
		TQString szPath=TQString::fromUtf8(path);
		return writeFile(szPath,szData,bAppend);
	}

	bool writeFileLocal8Bit(const TQString &szPath,const TQString &szData,bool bAppend)
	{
		KviFile f(szPath);
		if(!f.openForWriting(bAppend))return false;
		KviTQCString szTmp = TQTextCodec::codecForLocale()->fromUnicode(szData);
		if(!szTmp.data())return true;
		if(f.writeBlock(szTmp.data(),szTmp.length()) != ((int)(szTmp.length())))return false;
		return true;
	}
	
	bool writeFileLocal8Bit(const char* path,const TQString &szData,bool bAppend)
	{
		TQString szPath=TQString::fromUtf8(path);
		return writeFileLocal8Bit(szPath,szData,bAppend);
	}

	bool readFile(const TQString &szPath,TQString &szBuffer,unsigned int uMaxSize)
	{
		KviFile f(szPath);
		if(!f.openForReading())return false;
		if(f.size() < 1)
		{
			szBuffer = "";
			f.close();
			return true;
		}
		if(f.size() > uMaxSize)return false;
		char * buf = new char[f.size() + 1];
		if(f.readBlock(buf,f.size()) != ((long int)f.size()))
		{
			delete buf;
            buf = 0;
			return false;
		}
		buf[f.size()] = '\0';
		szBuffer = TQString::fromUtf8(buf);
		delete[] buf;
		return true;
	}

	bool readFile(const char* path,TQString &szBuffer,unsigned int uMaxSize)
	{
		TQString szPath=TQString::fromUtf8(path);
		return readFile(szPath,szBuffer,uMaxSize);
	}

	
	TQString extractFileName(const TQString &szFileNameWithPath)
	{
		return TQFileInfo(szFileNameWithPath).fileName();
	}

	TQString extractFilePath(const TQString &szFileNameWithPath)
	{
		return TQFileInfo(szFileNameWithPath).dirPath(true);
	}

	bool readLine(TQFile * f,TQString &szBuffer,bool bUtf8)
	{
		TQTextStream stream(f);
		stream.setEncoding(bUtf8 ? TQTextStream::UnicodeUTF8 : TQTextStream::Locale);
		szBuffer=stream.readLine();
		return !szBuffer.isNull();
	}
	
	bool readLines(TQFile * f,TQStringList &buffer,int iStartLine, int iCount, bool bUtf8)
	{
		TQTextStream stream( f );
		stream.setEncoding(bUtf8 ? TQTextStream::UnicodeUTF8 : TQTextStream::Locale);
		for(int i=0;i<iStartLine;i++)
			stream.readLine();

		if(iCount>0)
		{
			for(; (iCount>0 && !stream.atEnd()) ; iCount-- )
				buffer.append(stream.readLine());
		} else {
			while(!stream.atEnd()) {
				buffer.append(stream.readLine());
			}
		}
		return buffer.count()!= 0;
	}

	bool isReadable(const TQString &szFname)
	{
		TQFileInfo f(szFname);
		return (f.exists() && f.isFile() && f.isReadable());
	}
	
	bool isReadable(const char* path)
	{
		TQString szPath=TQString::fromUtf8(path);
		return isReadable(szPath);
	}
	
	bool isAbsolutePath(const TQString &szPath)
	{
		TQFileInfo f(szPath);
		return !f.isRelative();
	}
};

static char hexchars[16] = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' };


void kvi_encodeFileName(KviStr & path)
{
	TQString szPath(path.ptr());
	kvi_encodeFileName(szPath);
	path=szPath;
}

void kvi_encodeFileName(TQString & path)
{
	TQString src(path);
	path="";
	for(unsigned int i=0;i<src.length();i++)
	{
		TQChar cur=src[i];
		if( ! (cur.isLetter() || cur.isDigit() || cur==' ' || cur=='_' || cur=='.' || cur=='#' || cur=='%') )
		{
			if(cur.row()!=0)
			{
				path+='%';
				path+=hexchars[cur.row() >> 4];
				path+=hexchars[cur.row() & 15];
			}
			path+='%';
			path+=hexchars[cur.cell() >> 4];
			path+=hexchars[cur.cell() & 15];
		} else if (cur=='%')
		{
			path+="%%";
		} else {
			path+=cur;
		}
	}
}

//================ kvi_isAbsolutePath ===============//

bool kvi_isAbsolutePath(const TQString &path)
{
	if(path[0] == '/')return true;
	if(isalpha(path[0]))
	{
		if(path[1] == ':')return true;
	}
	return false;
}

//=================== kvi_readLine =====================//

bool kvi_readLine(TQFile *f,KviStr &str)
{
	TQTextStream stream(f);
	TQString szBuff=stream.readLine();
	str=szBuff;
	return szBuff.isNull() ? 1 : 0;
}


