/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <log4cxx/logstring.h>
#include <log4cxx/file.h>
#include <apr_file_io.h>
#include <apr_file_info.h>
#include <log4cxx/helpers/transcoder.h>
#include <log4cxx/helpers/pool.h>
#include <assert.h>
#include <log4cxx/helpers/exception.h>

using namespace LOG4CXX_NS;
using namespace LOG4CXX_NS::helpers;

struct File::FilePrivate{
	FilePrivate()
	{
		set_apr_path();
	}

	FilePrivate(const LogString& path)
		: path(path)
	{
		set_apr_path();
	}

	FilePrivate(const LogString& path, bool autoDelete)
		: path(path)
		, autoDelete(autoDelete)
	{
		set_apr_path();
	}

	LogString path;
	bool autoDelete{ false };
	Pool p;
	const char* apr_path{ nullptr };
	std::string encodedPath;

	const char* getPath() const;
	void set_apr_path();
};

File::File() :
	m_priv(std::make_unique<FilePrivate>())
{
}

template<class S>
static LogString decodeLS(const S* src)
{
	LogString dst;

	if (src != 0)
	{
		Transcoder::decode(src, dst);
	}

	return dst;
}

template<class S>
static LogString decodeLS(const std::basic_string<S>& src)
{
	LogString dst;
	Transcoder::decode(src, dst);
	return dst;
}


File::File(const std::string& name1)
	: m_priv(std::make_unique<FilePrivate>(decodeLS(name1)))
{
}

File::File(const char* name1)
	: m_priv(std::make_unique<FilePrivate>(decodeLS(name1)))
{
}

#if LOG4CXX_WCHAR_T_API
File::File(const std::wstring& name1)
	: m_priv(std::make_unique<FilePrivate>(decodeLS(name1)))
{
}

File::File(const wchar_t* name1)
	: m_priv(std::make_unique<FilePrivate>(decodeLS(name1)))
{
}
#endif


#if LOG4CXX_CFSTRING_API
File::File(const CFStringRef& name1)
	: m_priv(std::make_unique<FilePrivate>(decodeLS(name1)))
{
}
#endif

File::File(const File& src)
	: m_priv(std::make_unique<FilePrivate>(src.m_priv->path, src.m_priv->autoDelete))
{
}

File& File::operator=(const File& src)
{
	if (this == &src)
	{
		return *this;
	}

	m_priv->path.assign(src.m_priv->path);
	m_priv->autoDelete = src.m_priv->autoDelete;
	m_priv->set_apr_path();
	return *this;
}


File::~File()
{
	if(m_priv->autoDelete){
		deleteFile();
	}
}


LogString File::getPath() const
{
	return m_priv->path;
}

File& File::setPath(const LogString& newName)
{
	m_priv->path.assign(newName);
	m_priv->set_apr_path();
	return *this;
}

LogString File::getName() const
{
	const logchar slashes[] = { 0x2F, 0x5C, 0 };
	size_t lastSlash = m_priv->path.find_last_of(slashes);

	if (lastSlash != LogString::npos)
	{
		return m_priv->path.substr(lastSlash + 1);
	}

	return m_priv->path;
}

const char* File::FilePrivate::getPath() const
{
	return this->apr_path;
}

void File::FilePrivate::set_apr_path()
{
	this->encodedPath.clear();
	int style = APR_FILEPATH_ENCODING_UNKNOWN;
	apr_filepath_encoding(&style, this->p.getAPRPool());
	if (style == APR_FILEPATH_ENCODING_UTF8)
	{
		Transcoder::encodeUTF8(this->path, this->encodedPath);
	}
	else
	{
		Transcoder::encode(this->path, this->encodedPath);
	}

	for (auto& c : this->encodedPath)
	{
		if (c == '\\')
		{
			c = '/';
		}
	}
	this->apr_path = this->encodedPath.c_str();
}

const char* File::getAPRPath() const
{
	return m_priv->getPath();
}


bool File::exists() const
{
	apr_finfo_t finfo;
	apr_status_t rv = apr_stat(&finfo, m_priv->getPath(), 0, m_priv->p.getAPRPool());
	return rv == APR_SUCCESS;
}

bool File::deleteFile() const
{
	apr_status_t rv = apr_file_remove(m_priv->getPath(), m_priv->p.getAPRPool());
	return rv == APR_SUCCESS;
}

bool File::renameTo(const File& dest) const
{
	apr_status_t rv = apr_file_rename(m_priv->getPath(), dest.m_priv->getPath(), m_priv->p.getAPRPool());
	return rv == APR_SUCCESS;
}


size_t File::length() const
{
	apr_finfo_t finfo;
	apr_status_t rv = apr_stat(&finfo, m_priv->getPath(), APR_FINFO_SIZE, m_priv->p.getAPRPool());

	if (rv == APR_SUCCESS)
	{
		return (size_t) finfo.size;
	}

	return 0;
}


log4cxx_time_t File::lastModified() const
{
	apr_finfo_t finfo;
	apr_status_t rv = apr_stat(&finfo, m_priv->getPath(), APR_FINFO_MTIME, m_priv->p.getAPRPool());

	if (rv == APR_SUCCESS)
	{
		return finfo.mtime;
	}

	return 0;
}


std::vector<LogString> File::list() const
{
	apr_dir_t* dir;
	apr_finfo_t entry;
	std::vector<LogString> filenames;

	apr_status_t stat = apr_dir_open(&dir, m_priv->getPath(), m_priv->p.getAPRPool());

	if (stat == APR_SUCCESS)
	{
		int style = APR_FILEPATH_ENCODING_UNKNOWN;
		apr_filepath_encoding(&style, m_priv->p.getAPRPool());
		stat = apr_dir_read(&entry, APR_FINFO_DIRENT, dir);

		while (stat == APR_SUCCESS)
		{
			if (entry.name != NULL)
			{
				LogString filename;

				if (style == APR_FILEPATH_ENCODING_UTF8)
				{
					Transcoder::decodeUTF8(entry.name, filename);
				}
				else
				{
					Transcoder::decode(entry.name, filename);
				}

				filenames.push_back(filename);
			}

			stat = apr_dir_read(&entry, APR_FINFO_DIRENT, dir);
		}

		stat = apr_dir_close(dir);
	}

	return filenames;
}

LogString File::getParent() const
{
	LogString::size_type slashPos = m_priv->path.rfind(LOG4CXX_STR('/'));
	LogString::size_type backPos = m_priv->path.rfind(LOG4CXX_STR('\\'));

	if (slashPos == LogString::npos)
	{
		slashPos = backPos;
	}
	else
	{
		if (backPos != LogString::npos && backPos > slashPos)
		{
			slashPos = backPos;
		}
	}

	LogString parent;

	if (slashPos != LogString::npos && slashPos > 0)
	{
		parent.assign(m_priv->path, 0, slashPos);
	}

	return parent;
}

bool File::mkdirs() const
{
	apr_status_t stat = apr_dir_make_recursive(m_priv->getPath(), APR_OS_DEFAULT, m_priv->p.getAPRPool());
	return stat == APR_SUCCESS;
}

void File::setAutoDelete(bool autoDelete){
	m_priv->autoDelete = autoDelete;
}

bool File::getAutoDelete() const{
	return m_priv->autoDelete;
}

