/////////////////////////////////////////////////////////////////////////////
// File:        textfiledump.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 "textfiledump.h"

#include <stdio.h>

using namespace spcore;
using namespace std;

namespace mod_io {

TextFileDumpComponent::TextFileDumpComponent(const char * name, int argc, const char * argv[])
: CComponentAdapter(name, argc, argv)
{
	// Create pins and storage
	RegisterInputPin(*SmartPtr<IInputPin>(new InputPinPath(*this), false));
	RegisterInputPin(*SmartPtr<IInputPin>(new InputPinRefresh(*this), false));

	m_oPinContents= CTypeString::CreateOutputPin("contents");
	RegisterOutputPin(*m_oPinContents);
	
	m_contents= CTypeString::CreateInstance();
		
	// Process arguments
	if (argc) {
		for (int i= 0; i< argc; ++i) {
			if (argv[i] && strcmp ("-p", argv[i])== 0) {
				// Path
			
				++i;
				if (i< argc && argv[i]) m_path= argv[i];
				else throw std::runtime_error("textfile_dump. Missing value for option -p");
			}			
			else if (argv[i] && strlen(argv[i])) {
				string error_msg("textfile_dump. Unknown option:");
				error_msg+= argv[i];
				throw std::runtime_error(error_msg);
			}
		}
	}
}

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

	return 0;
}

void TextFileDumpComponent::Refresh ()
{
	if (!m_path.empty()) {
		
		size_t readbytes= 0;
		char* buff= NULL;

		FILE* file= fopen(m_path.c_str(), "rb");
		if (!file) {
			string error_msg("Cannot open file ");
			error_msg+= m_path;
			getSpCoreRuntime()->LogMessage(ICoreRuntime::LOG_ERROR, error_msg.c_str(), GetName());
			return;
		}

		// Obtain size
		fseek(file, 0L, SEEK_END);
		long size= ftell(file);
		fseek(file, 0L, SEEK_SET);

		if (size< 0) {
			string error_msg("Error reading file ");
			error_msg+= m_path;
			getSpCoreRuntime()->LogMessage(ICoreRuntime::LOG_ERROR, error_msg.c_str(), GetName());
			goto done;
		}
		else if (size> MAX_FILE_SIZE) {
			string error_msg("File too large ");
			error_msg+= m_path;
			getSpCoreRuntime()->LogMessage(ICoreRuntime::LOG_ERROR, error_msg.c_str(), GetName());
			goto done;
		}

		// Allocate buffer 
		buff= (char *) malloc (size + 1);
		if (!buff) {
			getSpCoreRuntime()->LogMessage(ICoreRuntime::LOG_ERROR, "Memory allocation failed.", GetName());
			goto done;
		}

		// Read contents
		readbytes= fread(buff, 1, size, file);
		if (ferror(file) || readbytes!= (size_t) size) {
			getSpCoreRuntime()->LogMessage(ICoreRuntime::LOG_ERROR, "Error reading file.", GetName());
			goto done_malloc;
		}
		buff[size]= 0;

		// Set to output value		
		m_contents->set(buff);

		// Send result
		m_oPinContents->Send(m_contents);

done_malloc:
		free (buff);

done:
		if (file) fclose(file);
	}
}

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

	if (newpath && m_path!= newpath && newpath[0]) {
		// Path changed and is not void
		m_path= newpath;
		Refresh();
	}
}

} // namespace spcore
