/*------------------------------------------------------------------------------*
 * File Name:				 													*
 * Creation: 																	*
 * Purpose: OriginC Source C file												*
 * Copyright (c) ABCD Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	Folger 07/28/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS						*
 *------------------------------------------------------------------------------*/
 
////////////////////////////////////////////////////////////////////////////////////
// Including the system header file Origin.h should be sufficient for most Origin
// applications and is recommended. Origin.h includes many of the most common system
// header files and is automatically pre-compiled when Origin runs the first time.
// Programs including Origin.h subsequently compile much more quickly as long as
// the size and number of other included header files is minimized. All NAG header
// files are now included in Origin.h and no longer need be separately included.
//
// Right-click on the line below and select 'Open "Origin.h"' to open the Origin.h
// system header file.
#include <Origin.h>
////////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////////
// Include your own header files here.
#include "wavelet_utils.h"

////////////////////////////////////////////////////////////////////////////////////
// Start your functions here.


uint get_enough_length_to_be_decompose(int nSignalLen, int nLevel)
{
	uint n, nMinSize;
	
	nMinSize = pow(2,nLevel);
	if(nSignalLen > nMinSize)
	{
		n=nSignalLen/128+(nSignalLen%128!=0?1:0);
		n=n*128;
	}
	else
	{
		n = nMinSize;
	}
	
	return n;
}


uint get_reconstruct_size(Nag_WavModeType mode, int nSizeofCoeffs, Nag_WavFilt& filter)
{
	int ny;
	if (mode == Nag_ZeroWavExt)
		ny = 2 * nSizeofCoeffs - MAX(filter.lrsh,filter.hrsh) + MAX(filter.nlr-1+filter.lrsh,filter.nhr-1+filter.hrsh);
	else
		ny = 2 * nSizeofCoeffs;
	
	return ny;
}

uint get_coeffs_size(Nag_WavModeType mode, int nSizeofSingal, Nag_WavFilt& filter)
{
	int nf = MAX(filter.nld, filter.nhd);
	int nc;
	
	//if (!strcmp("Periodic",vWaveMode[ext]))
	if (Nag_PerWavExt == mode)
	{
	  //mode = Nag_PerWavExt;
	  nc = (nSizeofSingal & 1 ? (nSizeofSingal + 1)/2 : nSizeofSingal/2);
	}
	//else if (!strcmp("Zero-padded",vWaveMode[ext]))
	else //(Nag_ZeroWavExt == mode)
	{
	  //mode = Nag_ZeroWavExt;
	  ///Sandy 2006-11-0-16 DEBUG
	  //nc = ((nSizeofSingal + nf - 1) & 1 ? (nSizeofSingal + nf)/2 : (nSizeofSingal + nf - 1)/2);
	  nc = ((nSizeofSingal + nf - 1) & 1 ? floor((nSizeofSingal + nf)/2) : floor((nSizeofSingal + nf - 1)/2));
	  //end
	}
	//else
	//{
	  //printf("mode type not recognised\n"); 
	  //goto END; 
	//}
	
	return nc;
}

bool create_wavelet_filter(Nag_WavType wavname, Nag_WavFilt &filter)
{
	NagError fail;
	//INIT_FAIL
	fail.code = NE_NOERROR;
	fail.print = 0;
	
	/* Initialise filter coefficients */
	nag_wavfilter(wavname, &filter, &fail);
	
	if (fail.code != NE_NOERROR)
	{
		nag_free_wavfilter(&filter);
		//printf(fail.message);
		return false;
	
	}
	
	return true;
}

bool multi_scale_dwt(int nLevel, Nag_WavModeType mode, vector& vSignal, Nag_WavFilt filter, vector& vCoeff, vector& vL)
{
	//double maxerr;
	NagError fail;
	//INIT_FAIL
	fail.code = NE_NOERROR;
	fail.print = 0;
	
	int n = vSignal.GetSize();
	int nf = MAX(filter.nld, filter.nhd);
	int nw=0;
	int nc=0;
	
	vector ca, cd, c;	
	//c.SetSize(n);
	c=vSignal;
	
	vL.SetSize(nLevel+1);
	
	for(int i=0;i<nLevel;i++)
	{
		
		if (mode == Nag_PerWavExt)
		{
		  nc = (n & 1 ? (n + 1)/2 : n/2);
			///Sandy 2008-3-10 add if decompose to the lowest level with perodic mode, should use padding and output warnning message
	      if(n%2 != 0)
	      {
	      	c.Add(c[0]);
	      	n = n+1;
	      	out_str(_L(" WARNING:Please Change DWT Extension Mode "));
	      }
			///end		  
		}
		else if (mode == Nag_ZeroWavExt)
		{
		  nc = ((n + nf - 1) & 1 ? (n + nf)/2 : (n + nf - 1)/2);
		}
		
		ca.SetSize(nc);
		cd.SetSize(nc);
		

		
		/* 1D Discrete Wavelet Transform (DWT) (one level) */
		nag_dwt(mode, n, c, &filter, nc, ca, cd, &fail);
		if (fail.code != NE_NOERROR)
		{
		  printf("Error from nag_dwt.\n%s\n", fail.message);
		  return false;
		}
		nw=vCoeff.GetSize();
		vCoeff.Append(cd);
		vCoeff.Wrap(nw);
		n=nc;
		c.SetSize(n);
		c=ca;
		vL[nLevel-i]=nc;
			
	}
	
	nw=vCoeff.GetSize();
	vCoeff.Append(ca);
	vCoeff.Wrap(nw);
	vL[0]=nc;
	
	return true;
}

bool multi_scale_idwt(int nLevel, Nag_WavModeType mode, vector& vSignal, Nag_WavFilt filter, vector& vCoeff, vector& vL)
{
	//double maxerr;
	NagError fail;

	//INIT_FAIL
	fail.code = NE_NOERROR;
	fail.print = 0;
	
	int nc=0;
	int nl=0;
	int ny=0;
	vector ca,cd,y;
	
	ca.SetSize(vL[0]);
	cd.SetSize(vL[1]);
	vCoeff.GetSubVector(ca, 0, vL[0]-1);
	vCoeff.GetSubVector(cd, vL[0], vL[0]+vL[1]-1);

	nl=vL[0];
	for(int i=0;i<nLevel;i++)
	{
		nc=vL[i+1];
		if(i!=0)
		{
			nc=min((int)y.GetSize(),nc);
			ca.SetSize(nc);
			cd.SetSize(nc);
			ca=y;
			nl+=vL[i];
			vCoeff.GetSubVector(cd, nl, nl+nc-1);
		}

		
				/* Reconstruction: Allocate array y */
		if (mode == Nag_ZeroWavExt)
		   ny = 2*nc-MAX(filter.lrsh,filter.hrsh) + 
		       MAX(filter.nlr-1+filter.lrsh,filter.nhr-1+filter.hrsh);
		else
		   ny = 2*nc;
		
		y.SetSize(ny);
		
		/* 1D Discrete Wavelet inverse Transform (IDWT) (one level) */
		nag_idwt(mode, nc, ca, cd, &filter, ny, y, &fail);
		
		if (fail.code != NE_NOERROR)
		{
		  printf("Error from nag_dwt.\n%s\n", fail.message);
		  return false;
		}	
			
	}
	
	vSignal.SetSize(ny);
	vSignal=y;
	return true;
	
}
	
//------ Folger 07/28/08 BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS
string	get_wavelet_type_string(int nType)
{
	vector<string>		vsTypes = {
		"Haar",
		"DB2",
		"DB3",
		"DB4",
		"DB5",
		"DB6",
		"DB7", 
		"DB8",
		"DB9",
		"DB10",
		"Bior1.1",
		"Bior1.3",
		"Bior1.5",
		"Bior2.2",
		"Bior2.4",
		"Bior2.6",
		"Bior2.8",
		"Bior3.1",
		"Bior3.3",
		"Bior3.5",
		"Bior3.7"
	};
	
	if ( nType < 0 || nType >= vsTypes.GetSize() )
	{
		ASSERT(false);
		return "";
	}

	return vsTypes[nType];
}
//------ End BETTER_OPREATION_OUTPUT_COLUMN_COMMENTS