//
//  LinearInterp.h
//  Qdos2 - Linear Interpolation Algorithm Template Functions
//
//  Janet Barnes
//  Oct 1999
//

#ifndef QDOS_LINEARINTERP_H
#define QDOS_LINEARINTERP_H

#include "Algorithm.h"
#ifdef QT_DEFINED
#include <qapplication.h>
#include <qprogressdialog.h>
#include <qmessagebox.h>
#endif

namespace QDOS {

// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ linear_interp
// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// ----------------------------------------------------------- linear_interp
template <class Tx, class Ty>
bool linear_interp( const NumericSequence<Tx>& x_data, \
    const NumericSequence<Ty>& y_data, const Tx& x_interp, Ty& y_interp)
{
// calculate the value of a function y=f(x) (as given by values of y, y_data,
// at values of x, x_data) at x_interp using linear interpolation
// floor_idx is the index of the greatest value of x such that
// x[floor_idx] <= x_interp
//

  int floor_idx = floor_index( x_data, x_interp );

  const int max_idx = x_data.size()-1;
  if (floor_idx==-1)
      y_interp=y_data[0];
  else if (floor_idx>=max_idx)
      y_interp=y_data[max_idx];
  else
  {
      double factor=( x_interp - x_data[floor_idx]) /  \
          (x_data[floor_idx+1]-x_data[floor_idx]);
      y_interp=y_data[floor_idx+1];
      y_interp-=y_data[floor_idx];
      y_interp*=factor;
      y_interp+=y_data[floor_idx];
      //y_interp=y_data[floor_idx] + \
      //    (y_data[floor_idx+1] - y_data[floor_idx]) * factor;
  }
  return true;
}

template <class Tx, class Ty>
bool linear_interp( const NumericSequence<Tx>& x_data, \
    const NumericSequence<Ty>& y_data, const Tx& x_interp, Ty& y_interp,\
    const Tx& gap_criterion)
{
// calculate the value of a function y=f(x) (as given by values of y, y_data,
// at values of x, x_data) at x_interp using linear interpolation
// floor_idx is the index of the greatest value of x such that
// x[floor_idx] <= x_interp
//

  int floor_idx = floor_index( x_data, x_interp );
  if (!interp_at_pt(x_data, x_interp, floor_idx, gap_criterion))
      return false;

  const int max_idx = x_data.size()-1;
  if (floor_idx==-1)
      y_interp=y_data[0];
  else if (floor_idx>=max_idx)
      y_interp=y_data[max_idx];
  else
  {
      double factor=( x_interp - x_data[floor_idx]) /  \
          (x_data[floor_idx+1]-x_data[floor_idx]);
      y_interp=y_data[floor_idx+1];
      y_interp-=y_data[floor_idx];
      y_interp*=factor;
      y_interp+=y_data[floor_idx];
  }
  return true;
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++ series_linear_interp
// ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// ----------------------------------------------------- series_linear_interp
template<class Tx, class Ty>
vector<bool> series_linear_interp( const NumericSequence<Tx>& x_data, \
    const NumericSequence<Ty>& y_data, const NumericSequence<Tx>& x_interp, \
    NumericSequence<Ty>& y_interp )
{
// perform linear interpolation to find value of a function y=f(x), with
// values of y, y_data, provided at  values of x, x_data, at points x_interp
    data_is_ok(x_data,y_data);
#ifdef DIAG
    cout << "Start of Series Linear Interpolation (Ignore gaps) " << endl;
#endif
    int sz=x_interp.size();
    vector<bool> mask(sz,false);
    y_interp.resize(sz);
#ifdef QT_DEFINED
     QProgressDialog progress_dlg("Interpolating,,,","Abort",sz,0,"progress",TRUE);
     progress_dlg.setCaption("MultiJoin");
     progress_dlg.show();
     qApp->processEvents();
#endif
     for(register int i=sz-1;i>=0;i--)
     {
#ifdef QT_DEFINED
	 progress_dlg.setProgress(sz-i);
	 qApp->processEvents();
	 if(progress_dlg.wasCancelled())
	 {
	   switch(QMessageBox::warning(0,"MultiJoin","Abort?",
	     QMessageBox::No | QMessageBox::Default,
	     QMessageBox::Yes, QMessageBox::Cancel | QMessageBox::Escape))
           {
	     case QMessageBox::Yes:
	      cout << "Linear Interpolation Aborted" << endl;
	      throw QDOS::Exception("MultiJoin Aborted");
	      break;

	     case QMessageBox::No:
	     case QMessageBox::Cancel:
	     default:
	        progress_dlg.reset();
		progress_dlg.setLabelText("Interpolating...");
		progress_dlg.setProgress(sz-i);
		progress_dlg.show();
		qApp->processEvents();

		break;
	   }
	 }
#endif
        mask[i]=linear_interp( x_data, y_data, x_interp[i],y_interp[i] );
    }
#ifdef DIAG
    cout << "End of Series Linear Interpolation (Ignore gaps) " << endl;
#endif
    return mask;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++ series_linear_interp
// ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// ----------------------------------------------------- series_linear_interp

template <class Tx, class Ty>
vector<bool> series_linear_interp( const NumericSequence<Tx>& x_data, \
const NumericSequence<Ty>& y_data, NumericSequence<Tx>& x_interp, \
NumericSequence<Ty>& y_interp, const Tx& gap_criterion)
{
// perform linear interpolation to find value of a function y=f(x), with
// values of y, y_data, provided at  values of x, x_data, at points x_interp.
// The value gap_criterion is used to determine whether or not a value for
// y can be interpolated at each x_interp. Remove Gaps
     data_is_ok(x_data,y_data);
#ifdef DIAG
    cout << "Start of Series Linear Interpolation (Remove gaps) " << endl;
#endif
     int sz=x_interp.size();
     vector<bool> mask(sz,false);
     y_interp.resize(sz);
#ifdef QT_DEFINED
     QProgressDialog progress_dlg("Interpolating,,,","Abort",sz,0,"progress",TRUE);
     progress_dlg.setCaption("MultiJoin");
     progress_dlg.show();
     qApp->processEvents();
#endif
     for(register int i=sz-1;i>=0;i--)
     {
#ifdef QT_DEFINED
	 progress_dlg.setProgress(sz-i);
	 qApp->processEvents();
	 if(progress_dlg.wasCancelled())
	 {
	   switch(QMessageBox::warning(0,"MultiJoin","Abort?",
	     QMessageBox::No | QMessageBox::Default,
	     QMessageBox::Yes, QMessageBox::Cancel | QMessageBox::Escape))
           {
	     case QMessageBox::Yes:
	      cout << "Linear Interpolation Aborted" << endl;
	      throw QDOS::Exception("MultiJoin Aborted");
	      break;

	     case QMessageBox::No:
	     case QMessageBox::Cancel:
	     default:
	        progress_dlg.reset();
		progress_dlg.setLabelText("Interpolating...");
		progress_dlg.setProgress(sz-i);
		progress_dlg.show();
		qApp->processEvents();

		break;
	   }
	 }
#endif
         mask[i]=linear_interp( x_data, y_data, x_interp[i],y_interp[i],\
             gap_criterion);
     }

     vector<bool> emask(!mask);
     x_interp.erase(emask);
     y_interp.erase(emask);
#ifdef DIAG
    cout << "End of Series Linear Interpolation (Remove gaps) " << endl;
#endif
     return mask;
}

// +++++++++++++++++++++++++++++++++++++++++++++++++++++ series_linear_interp
// ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// ----------------------------------------------------- series_linear_interp
template<class Tx, class Ty>
vector<bool> series_linear_interp( const NumericSequence<Tx>& x_data, \
const NumericSequence<Ty>& y_data, NumericSequence<Tx>& x_interp, \
NumericSequence<Ty>& y_interp, const Tx& gap_criterion, const Ty& fill_value )
{
// perform linear interpolation to find value of a function y=f(x), with
// values of y, y_data, provided at  values of x, x_data, at points x_interp.
// The value gap_criterion is used to determine whether or not a value for
// y can be interpolated at each x_interp. Fill Gaps
    data_is_ok(x_data,y_data);
#ifdef DIAG
    cout << "Start of Series Linear Interpolation (Fill gaps) " << endl;
#endif
     int sz=x_interp.size();
     vector<bool> sm(sz,false);
     y_interp.resize(sz);
#ifdef QT_DEFINED
     QProgressDialog progress_dlg("Interpolating,,,","Abort",sz,0,"progress",TRUE);
     progress_dlg.setCaption("MultiJoin");
     progress_dlg.show();
     qApp->processEvents();
#endif
     for(register int i=sz-1;i>=0;i--)
     {
#ifdef QT_DEFINED
	 progress_dlg.setProgress(sz-i);
	 qApp->processEvents();
	 if(progress_dlg.wasCancelled())
	 {
	   switch(QMessageBox::warning(0,"MultiJoin","Abort?",
	     QMessageBox::No | QMessageBox::Default,
	     QMessageBox::Yes, QMessageBox::Cancel | QMessageBox::Escape))
           {
	     case QMessageBox::Yes:
	      cout << "Linear Interpolation Aborted" << endl;
	      throw QDOS::Exception("MultiJoin Aborted");
	      break;

	     case QMessageBox::No:
	     case QMessageBox::Cancel:
	     default:
	        progress_dlg.reset();
		progress_dlg.setLabelText("Interpolating...");
		progress_dlg.setProgress(sz-i);
		progress_dlg.show();
		qApp->processEvents();

		break;
	   }
	 }
#endif
         sm[i]=linear_interp(x_data,y_data,x_interp[i],y_interp[i],\
             gap_criterion);
	 if(!sm[i])
             y_interp[i]=fill_value;
     }
#ifdef DIAG
     cout << "End of Series Linear Interpolation (Fill gaps) " << endl;
#endif
     return sm;
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++ series_linear_interp
// ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// ----------------------------------------------------- series_linear_interp
template<class Tx, class Ty>
vector<bool> series_linear_interp( const NumericSequence<Tx>& x_data, \
const NumericSequence<Ty>& y_data, NumericSequence<Tx>& x_interp, \
NumericSequence<Ty>& y_interp, const Tx& gap_criterion,
bool (*pinterp_fn)(const NumericSequence<Tx>&, const NumericSequence<Ty>&,
const Tx&,Ty&) )
{
// perform linear interpolation to find value of a function y=f(x), with
// values of y, y_data, provided at  values of x, x_data, at points x_interp.
// The value gap_criterion is used to determine whether or not a value for
// y can be interpolated at each x_interp. Interpolate over gaps, using names function
//
    data_is_ok(x_data,y_data);
#ifdef DIAG
    cout << "Start of Series Linear Interpolation (Interpolate over gaps) " << endl;
#endif
    int sz=x_interp.size();
     vector<bool> sm(sz,false);
     y_interp.resize(sz);
     if(pinterp_fn==NULL)
       pinterp_fn=linear_interp;

#ifdef QT_DEFINED
     QProgressDialog progress_dlg("Interpolating,,,","Abort",sz,0,"progress",TRUE);
     progress_dlg.setCaption("MultiJoin");
     progress_dlg.show();
     qApp->processEvents();
#endif
     for(register int i=sz-1;i>=0;i--)
     {
#ifdef QT_DEFINED
	 progress_dlg.setProgress(sz-i);
	 qApp->processEvents();
	 if(progress_dlg.wasCancelled())
	 {
	   switch(QMessageBox::warning(0,"MultiJoin","Abort?",
	     QMessageBox::No | QMessageBox::Default,
	     QMessageBox::Yes, QMessageBox::Cancel | QMessageBox::Escape))
           {
	     case QMessageBox::Yes:
	      cout << "Linear Interpolation Aborted" << endl;
	      throw QDOS::Exception("MultiJoin Aborted");
	      break;

	     case QMessageBox::No:
	     case QMessageBox::Cancel:
	     default:
	        progress_dlg.reset();
		progress_dlg.setLabelText("Interpolating...");
		progress_dlg.setProgress(sz-i);
		progress_dlg.show();
		qApp->processEvents();

		break;
	   }
	 }
#endif
         sm[i]=linear_interp(x_data,y_data,x_interp[i],y_interp[i],\
             gap_criterion);
	 if(!sm[i])
           (*pinterp_fn)(x_data,y_data,x_interp[i],y_interp[i]);
     }

#ifdef DIAG
     cout << "End of Series Linear Interpolation (Interpolate over gaps) " << endl;
#endif
     return sm;
}



}  // end namespace QDOS
#endif
