/////////////////////////////////////////////////////////////////////////////
// File:        filebrowser.cpp
// Author:      Cesar Mauri Loba (cesar at crea-si dot com)
// Copyright:   (C) 2010-11 Cesar Mauri Loba - CREA Software Systems
//
//  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 "filebrowser.h"

#define BOOST_FILESYSTEM_VERSION 3
#define BOOST_FILESYSTEM_NO_DEPRECATED 1
#include <boost/filesystem.hpp>

#ifndef NDEBUG
#include <iostream>
#endif

using namespace spcore;
using namespace boost::filesystem;
using namespace std;

namespace mod_io {

FileBrowserComponent::FileBrowserComponent(const char * name, int argc, const char * argv[])
: CComponentAdapter(name, argc, argv)
, m_selectDirs(false)

{
	// Create pins and storage
	RegisterInputPin(*SmartPtr<IInputPin>(new InputPinPath(*this), false));
	RegisterInputPin(*SmartPtr<IInputPin>(new InputPinRefresh(*this), false));

	m_oPinPaths= CTypeAny::CreateOutputPinAny("paths");
	RegisterOutputPin(*m_oPinPaths);
	m_oPinFiles= CTypeAny::CreateOutputPinAny("files");
	RegisterOutputPin(*m_oPinFiles);

	m_pathNames= CTypeComposite::CreateInstance();
	m_fileNames= CTypeComposite::CreateInstance();
	
	// Process arguments
	if (argc) {
		for (int i= 0; i< argc; ++i) {
			if (strcmp ("-p", argv[i])== 0) {
				// Path
			
				++i;
				if (i< argc) m_currentPath= argv[i];
				else throw std::runtime_error("file_browser. Missing value for option -p");
			}
			else if (strcmp ("-t", argv[i])== 0) {
				// Type of listing
				++i;

				char opt= 0;

				if (i< argc && (opt= argv[i][0]) && argv[i][1]== 0 && (opt== 'd' || opt== 'a' )) {
					if (opt== 'd') m_selectDirs= true;
					else m_selectDirs= false;
				}
				else throw std::runtime_error("file_browser. Wrong value for option -t. Use either d or a.");				
			}
			else if (strcmp ("-w", argv[i])== 0) {
				// Wildcard 
				
				// TODO
				assert (false);

				++i;

				if (i== argc) throw std::runtime_error("file_browser. Missing value for -w argument.");
				m_wildcard= argv[i];
			}
			else if (strlen(argv[i])) {
				string error_msg("file_browser. Unknown option:");
				error_msg+= argv[i];
				throw std::runtime_error(error_msg);
			}
		}
	}
}

int FileBrowserComponent::DoInitialize()
{
	Refresh();

	return 0;
}

void FileBrowserComponent::Refresh ()
{
	if (!m_currentPath.empty() && ReScanPath (m_currentPath.c_str())) {
		// Send result
		m_oPinPaths->Send(m_pathNames);
		m_oPinFiles->Send(m_fileNames);
	}
}

void FileBrowserComponent::OnPinPath (const CTypeString & msg)
{
	const char* newpath= msg.get();

	if (newpath && m_currentPath!= newpath && newpath[0]) {
		// Path changed and is not void
		if (ReScanPath (newpath)) {
			m_currentPath= newpath;
			m_oPinPaths->Send(m_pathNames);
			m_oPinFiles->Send(m_fileNames);
		}
	}
}

bool FileBrowserComponent::ReScanPath (const char* path_name)
{
	// Check path
	try {
		path p(path_name);

		// Is directory?
		if (!is_directory(p)) {
			std::string error_msg("Path ");
			error_msg+= path_name;
			error_msg+= " is not a directory.";
			getSpCoreRuntime()->LogMessage(ICoreRuntime::LOG_ERROR, error_msg.c_str(), "filebrowser");
			return false;
		}

		// Create result holders
		SmartPtr<CTypeComposite> resultPaths= CTypeComposite::CreateInstance();
		SmartPtr<CTypeComposite> resultNames= CTypeComposite::CreateInstance();

		// List contents
		vector<string> pathList, nameList;

		directory_iterator end_it;	// Default ctor yields past-the-end
		for(directory_iterator dit(p); dit!= end_it; ++dit) {
			if ((m_selectDirs && is_directory(dit->path())) || (!m_selectDirs && is_regular_file(dit->path())) ) {
				// Workaround to cope with both BOOST_FILESYSTEM_VERSION 2 and 3
				pathList.push_back(dit->path().string().c_str());
				path tmpfname(dit->path().filename());
				nameList.push_back(tmpfname.string().c_str());
			}
		}

		// Sort
		sort(pathList.begin(), pathList.end());
		sort(nameList.begin(), nameList.end());

		vector<string>::const_iterator itp= pathList.begin();
		vector<string>::const_iterator itn= nameList.begin();
		for (; itp!= pathList.end() && itn!= nameList.end(); ++itp, ++itn) {
			SmartPtr<CTypeString> strPath= CTypeString::CreateInstance();
			strPath->set(itp->c_str());
			resultPaths->AddChild(strPath);

			SmartPtr<CTypeString> strName= CTypeString::CreateInstance();
			strName->set(itn->c_str());
			resultNames->AddChild(strName);
		}
		assert (itp== pathList.end() && itn== nameList.end());

		// Update internal instances
		m_pathNames= resultPaths;
		m_fileNames= resultNames;
	}
	catch (const std::exception& ex) {
		getSpCoreRuntime()->LogMessage(ICoreRuntime::LOG_ERROR, ex.what(), "filebrowser");
		return false;
	}

	return true;
}

} // namespace spcore
