// 
//  Adapter.h
//  Qdos2 - Classes for "adapting" generic QdObject class arguments to
//  template function arguments
//
//  Janet Barnes
//  Sept 2000
//

#ifndef QDOS_ADAPTER_H
#define QDOS_ADAPTER_H

#include "Exception.h"
#include "Var.h"
#include "JoinObject.h"
#include "QObject.h"

namespace QDOS {

class FunctionAdapterException: public Exception
{
public:
    FunctionAdapterException(ExceptionMsg m=""):\
        Exception(m<<"[FunctionAdapterException]"){;}
};
class BadAdapter: public FunctionAdapterException
{
public:
    BadAdapter(ExceptionMsg m=""):\
        FunctionAdapterException(m<<"[BadAdapter]"){;}
};


class FunctionAdapter
{
public:
    virtual ~FunctionAdapter(){;}
    virtual void run()=0;
};

template<class Tx> class MultiJoinAdapter;

template<class Tx,class Ty>
class JoinAdapter:public FunctionAdapter, public JoinObject<Tx,Ty>
{
    friend class MultiJoinAdapter<Tx>;
    
public:
    JoinAdapter(QdObject_var x_in, QdObject_var y_in, QdObject_var x_out,\
        QdObject_var y_out,QdObject_var join_method,\
        QdObject_var gap_value,QdObject_var gap_handler)
    {
        JoinObject<Tx,Ty>& _join_obj=*this;
        NumericSequence<Tx>* _x_in=\
            dynamic_cast<NumericSequence<Tx>* >(x_in.ptr_());
        NumericSequence<Ty>* _y_in=\
            dynamic_cast<NumericSequence<Ty>* >(y_in.ptr_());
        NumericSequence<Tx>* _x_out=\
            dynamic_cast<NumericSequence<Tx>* >(x_out.ptr_());
        NumericSequence<Ty>* _y_out=\
            dynamic_cast<NumericSequence<Ty>* >(y_out.ptr_()); 
        Interp<Tx,Ty>* _join_method;
        string* interp_type=dynamic_cast<string*>(join_method.ptr_());
        if(interp_type!=0)
            _join_method=get_interp_type(*interp_type); 
            
        Tx* _gap_value=dynamic_cast<Tx*>(gap_value.ptr_());
        if(_gap_value==0)
        {
        // ignore gaps 
            _join_obj=JoinObject<Tx,Ty>(_x_in,_y_in,_x_out,_y_out,\
                _join_method);
            return;
        }
        Ty* _fill_value=dynamic_cast<Ty*>(gap_handler.ptr_());
        if(_fill_value!=0)
        {
        // fill gaps
            _join_obj=JoinObject<Tx,Ty>(_x_in,_y_in,_x_out,_y_out,\
                _join_method,*_gap_value,*_fill_value);
            return;
        }
        string* gap_interp_type=dynamic_cast<string*>(gap_handler.ptr_());
        Interp<Tx,Ty>* _gap_interp;
        if(gap_interp_type!=0)
        {
        // interpolate over gaps
             _gap_interp=get_interp_type(*gap_interp_type);
             _join_obj=JoinObject<Tx,Ty>(_x_in,_y_in,_x_out,_y_out,\
                 _join_method,*_gap_value,_gap_interp);
             return;
             
        }
        else
            _join_obj=JoinObject<Tx,Ty>(_x_in,_y_in,_x_out,_y_out,\
                 _join_method,*_gap_value); // remove gaps
    }
    
    virtual ~JoinAdapter(){;}
    
    static Interp<Tx,Ty>* get_interp_type(string str)
    {
        static InterpTypes<Tx,Ty> interp_types;
        Interp<Tx,Ty>* interp_method=interp_types.get_interp_type(str);
        return interp_method;
    }  
  
    virtual void run()
    { vector<bool> msk=JoinObject<Tx,Ty>::join(); }
};

template<class Tx>
class MultiJoinAdapter:public FunctionAdapter, public MultiJoinObject<Tx>
{
    int _triage_cnt;

public:
    MultiJoinAdapter(QdObjectSeq_var x_in, QdObjectSeq_var y_in, \
        QdObject_var x_out, QdObjectSeq_var y_out, \
        QdObjectSeq_var join_method, QdObjectSeq_var gap_value,\
        QdObjectSeq_var gap_handler,int triage_cnt):_triage_cnt(triage_cnt)
    {
        // check sizes are conformant
        int n=x_in->size();
        NumericSequence<Tx>* join_pts=\
            dynamic_cast<NumericSequence<Tx>*>(x_out.ptr_());
        if(!join_pts)
            throw BadAdapter("[MultiJoinAdapter]");
        set_join_points(join_pts);
        for(int i=0;i<n;i++)
        {
            FunctionAdapter* adapter=y_in[i]->join(x_in[i],y_in[i],x_out,\
                y_out[i],join_method[i],gap_value[i],\
                gap_handler[i]);
            JoinKey<Tx>* join_object=\
                dynamic_cast<JoinKey<Tx>*>(adapter);
            if(join_object==0)
                throw BadJoin("Invalid JoinKey");
            assign(join_object);
        }
    }
    
    virtual ~MultiJoinAdapter(){;}
  
    virtual void run()
    {
        vector<bool> msk=MultiJoinObject<Tx>::multijoin(_triage_cnt);
    }
};    
        

}  // end namespace QDOS
#endif
                    

        
