#include "wenerator_t.h"


void   wenerator_t_setup(void){
    pcWenerator_t = class_new(gensym("wenerator_tilde"),
          (t_newmethod)wenerator_t_new, (t_method)wenerator_t_delete,
          sizeof(sWenerator_t),
          CLASS_DEFAULT,
          A_DEFFLOAT, 0);
    class_addmethod(pcWenerator_t, (t_method)wenerator_t_dsp, gensym("dsp"), 0);
    CLASS_MAINSIGNALIN(pcWenerator_t, sWenerator_t, fConstSignal);
    class_addbang(pcWenerator_t, wenerator_t_bang);
    class_addmethod(pcWenerator_t, (t_method)wenerator_t_wenerate, gensym("wenerate"), A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, A_DEFFLOAT, 0);
}
void  *wenerator_t_new(t_floatarg fArg UNUSED){
    struct _sWenerator_t *psW=(sWenerator_t *) pd_new(pcWenerator_t);
    
    psW->x_inC = inlet_new(&(psW->x_obj), &(psW->x_obj.ob_pd), &s_signal, &s_signal);
    psW->x_in=inlet_new(&psW->x_obj, &psW->x_obj.ob_pd, &s_list, gensym("wenerate"));
    
    psW->x_outG=outlet_new(&(psW->x_obj), &s_signal);
    psW->x_outC=outlet_new(&(psW->x_obj), &s_signal);
    psW->x_outM = outlet_new(&(psW->x_obj), &s_float);
    
    psW->pawc_intern = wabor_t_malloc0((WENERATOR_T_MAX_AST_COEFF+1) * sizeof *(psW->pawc_intern));
    psW->pawc[0] = wabor_t_malloc0((WENERATOR_T_MAX_AST_COEFF+1) * sizeof *(psW->pawc[0]));
    
    psW->pawc_intern[0].numCoeff=0;
    psW->pawc[0][0].numCoeff=0;
    
    
    return (void *)psW;
}
void   wenerator_t_delete(sWenerator_t *psW){
    
    inlet_free(psW->x_inC);
    psW->x_inC=NULL;
    inlet_free(psW->x_in);
    psW->x_in=NULL;
    
    outlet_free(psW->x_outM);
    psW->x_outM=NULL;
    outlet_free(psW->x_outG);
    psW->x_outG=NULL;
    outlet_free(psW->x_outC);
    psW->x_outG=NULL;
    
    wabor_t_free(psW->pawc_intern);
    psW->pawc_intern=NULL;
    wabor_t_free(psW->pawc[0]);
    psW->pawc[0]=NULL;
}

void   wenerator_t_dsp(sWenerator_t *psW, t_signal **sp){
    #define WENERATOR_T_PERFORM_NUM_POINTERS (4)
    dsp_add(wenerator_t_perform, WENERATOR_T_PERFORM_NUM_POINTERS,
            psW,
            sp[1]->s_vec,
            sp[2]->s_vec,
            sp[3]->s_vec
            );
}
t_int *wenerator_t_perform(t_int *aw){
    struct _sWenerator_t    *psW = (sWenerator_t*)(aw[1]);
    t_sample *inC   =  (t_sample *)(aw[2]);
    t_sample *outG  =  (t_sample *)(aw[3]);
    t_sample *outC  =  (t_sample *)(aw[4]);
        
    memset(outG, 0, PD_BLOCKSIZE * sizeof *outG);
    
    if(   find_int_at_address(&inC[WABOR_T_MAGIC_NUMBER_BIN]) != WABOR_T_MAGIC_NUMBER_C  )   {
        memset(outG,0 , PD_BLOCKSIZE * sizeof *outG);
        memset(outC,0 , PD_BLOCKSIZE * sizeof *outC);
        return aw + WENERATOR_T_PERFORM_NUM_POINTERS + 1; //Wenn ich nicht mit wabor_t verbunden bin
    }
    
    t_int num=psW->num_coeff;
    if(num>WENERATOR_T_MAX_AST_COEFF || num<0){
        error("wenerator: Fatal Error."); //DEBUG
        return (aw + WENERATOR_T_PERFORM_NUM_POINTERS + 1);
    }    
    
    psW->pawc[0][0].numCoeff=num;    
    while(num--){
        psW->pawc[0][num].val_r=psW->pawc_intern[num].val_r;
        psW->pawc[0][num].val_i=psW->pawc_intern[num].val_i;
        psW->pawc[0][num].start=psW->pawc_intern[num].start;
        psW->pawc[0][num].band=psW->pawc_intern[num].band;
    }
    
    
    hide_int_at_address( 1, &outG[WABOR_T_NUM_BLOCKS_BIN]);
    hide_int_at_address( WABOR_T_MAGIC_NUMBER_G,  &outG[WABOR_T_MAGIC_NUMBER_BIN]);
    hide_pointer_at_address(psW->pawc,    &outG[WABOR_T_POINTER_TO_COEFF_BIN]);
    psW->num_coeff=0;
    return (aw + WENERATOR_T_PERFORM_NUM_POINTERS + 1);
    
}
#undef WENERATOR_T_PERFORM_NUM_POINTERS

void   wenerator_t_bang(sWenerator_t UNUSED *psW){
    post("Wenerator Bang Bang Boing");
}

void   wenerator_t_wenerate(sWenerator_t *psW, t_floatarg fTime, t_floatarg Val_real, t_floatarg Val_imag, t_floatarg fBand){
    
    t_int *piNum=&psW->num_coeff;
    
    if(*piNum<WENERATOR_T_MAX_AST_COEFF) {
        //Coeffizient hinzufuegen
        t_int time=fTime;
        if(time<0)time=0;
        if(time>=PD_BLOCKSIZE) time=PD_BLOCKSIZE-1;
        t_int band=fBand;
        if(band<0) band=0;
        
        psW->pawc_intern[*piNum].val_i=Val_imag;
        psW->pawc_intern[*piNum].val_r=Val_real;
        psW->pawc_intern[*piNum].start = time;
        psW->pawc_intern[*piNum].band=band;
        ++(*piNum);
        if(*piNum==WENERATOR_T_MAX_AST_COEFF){
            post("wenerator: Maximum number of events for wenerator reached.");
        }
        if((*piNum)>WENERATOR_T_MAX_AST_COEFF){
            error("wenerator: Fatal Error."); //DEBUG
        }
    }
    return;
}
