//==============================================================================
/*! \file
 * OpenMesh Toolkit for mesh analysis    \n
 * Copyright (c) 2010 by Rostislav Hulik     \n
 *
 * Author:  Rostislav Hulik, rosta.hulik@gmail.com  \n
 * Date:    2010/10/25                          \n
 *
 * This file is part of software developed for support of Rostislav Hulik's dissertation thesis at dcgm-robotics@FIT group.
 *
 * This file is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This file 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this file.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Module description:
 * - Module reads a file specified in -file argument
 * - Result is sent to connected MDSTk channel
 */

#include "GaussianFilter.h"

#include <math.h>

///////////////////////////////////////////////////////////////////////////////////////////////////
// Module constants
///////////////////////////////////////////////////////////////////////////////////////////////////

// Module description
const std::string MODULE_DESCRIPTION    = "Module that computes N x N Gaussian filter";

// Additional command line arguments (input file)
const std::string MODULE_ARGUMENTS      = "dev:size:normalize";

// Additional arguments (input file)
const std::string MODULE_ARG_DEVIATION	= "dev";
const std::string MODULE_ARG_NORM		= "normalize";
const std::string MODULE_ARG_SIZE		= "size";

const double	MODULE_DEVIATION_DEFAULT	= 1.0;
const int		MODULE_SIZE_DEFAULT			= 3;
const bool		MODULE_NORM_DEFAULT			= false;

///////////////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////////////
OMLoadFile::OMLoadFile(const std::string& sDescription) : mds::mod::CModule(sDescription)
{
    allowArguments(MODULE_ARGUMENTS);
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Destructor
///////////////////////////////////////////////////////////////////////////////////////////////////
OMLoadFile::~OMLoadFile()
{
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Do on startup
///////////////////////////////////////////////////////////////////////////////////////////////////
bool OMLoadFile::startup()
{    
	// Note
    MDS_LOG_NOTE("Module startup");

    // Test of existence of input and output channel
    if( getNumOfInputs() != 1 || getNumOfOutputs() != 1 )
    {
        MDS_CERR('<' << m_sFilename << "> Wrong number of input and output channels" << std::endl);
        return false;
    }

	m_deviation = MODULE_DEVIATION_DEFAULT;
	m_Arguments.value(MODULE_ARG_DEVIATION, m_deviation);

	m_normalize = MODULE_NORM_DEFAULT;
	if (m_Arguments.exists(MODULE_ARG_NORM)) m_normalize = !MODULE_NORM_DEFAULT;

	m_size = MODULE_SIZE_DEFAULT;
	m_Arguments.value(MODULE_ARG_SIZE, m_size);
	
	if (m_size < 1)
	{
		MDS_CERR('<' << m_sFilename << "> Size must be bigger than 0." << std::endl);
        printUsage();
        return false;
	}

    // O.K.
    return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Main module loop
///////////////////////////////////////////////////////////////////////////////////////////////////
bool OMLoadFile::main()
{
    // Note
    MDS_LOG_NOTE("Module main function");

    // I/O channels
    mds::mod::CChannel *pOChannel = getOutput(0);

	std::stringstream str;
	int center = m_size/2;

	str << "Matrix " << m_size << " " << m_size << " " << std::endl;
	
	double down = sqrt(2 * M_PI) * m_deviation;
	double expDown = 2 * m_deviation * m_deviation;
	double realX, realY;
	for (int y = 0; y < m_size; ++y)
	{
		str << std::endl;
		for (int x = 0; x < m_size; ++x)
		{
			realX = (double)x - center;
			realY = (double)y - center;
			if (m_normalize)
				str << exp(-(realX*realX + realY*realY)/expDown) << " ";
			else
				str << exp(-(realX*realX + realY*realY)/expDown)/down << " ";
		}
	}

	if (!pOChannel->write(str.str().c_str(), str.str().length()-1))
	{
		MDS_CERR('<' << m_sFilename << "> Failed to write output data" << std::endl);
		return false;
	}
	
	return false;
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// On module shutdown
///////////////////////////////////////////////////////////////////////////////////////////////////
void OMLoadFile::shutdown()
{
    // Note
    MDS_LOG_NOTE("Module shutdown");
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Writes extended use of this module
///////////////////////////////////////////////////////////////////////////////////////////////////
void OMLoadFile::writeExtendedUsage(std::ostream& Stream)
{
    MDS_CERR("Necessary arguments: [-file filename]" << std::endl);
    MDS_CERR("Options:" << std::endl);
	MDS_CERR("  -file Specifies input file." << std::endl);
	MDS_CERR("	  -Format is determined from a file (allowed are STL, OFF, OBJ, PLY, OM)." << std::endl);
    MDS_CERR(std::endl);
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Main - executing a module
///////////////////////////////////////////////////////////////////////////////////////////////////
int main(int argc, char *argv[])
{
    // Creation of a module using smart pointer
    OMLoadFilePtr spModule(new OMLoadFile(MODULE_DESCRIPTION));

    // Initialize and execute the module
    if( spModule->init(argc, argv) )
    {
        spModule->run();
    }

    // Console application finished
    return 0;
}

