/* -*- mode: c++; c-basic-offset: 3 -*-
 *
 * PANTHEON Project
 *
 * GREYC IMAGE
 * 6 Boulevard Maréchal Juin
 * F-14050 Caen Cedex France
 *
 * This file is free software. You can use it, distribute it
 * and/or modify it. However, the entire risk to the quality
 * and performance of this program is with you.
 *
 * Please email any bugs, comments, and/or additions to this file to:
 * pandore@greyc.ensicaen.fr
 * http://www.greyc.ensicaen.fr/EquipeImage/Pandore/
 */

/**
 * Projet 3A : WAVEATOM transform
 * @author Mahmoud Ghoniem 
 * @date 2006-11-20
 *
 */

/*
 * @file freq_pat.cpp
 * @brief Generate frequency partition
 */

#include <math.h>
#include <complex>
using namespace std;
#include "complexe.h"
using namespace pandore;

/**
 * Function freq_pat
 * @param H : half length of the frequency span.
 *            H needs to be greater than 16
 * @param pat : type of frequency partition which satisfies parabolic scaling relationship
 *              equal to 'p' or 'q'
 * @output lst: A collection containing the frequency partition
 *
 * generate frequency partition
 */
Errc Freq_pat(Img1duc*& lst, int H, char pat) {

   if (H<16) cerr<<"H needs to be at least 16"<<endl;

   int len, cnt, idx, rad, old, trg;
 
   if (pat == 'p')// Parabolic scaling by Lexing
      {
	 len = (int) ceil(log2((double)H)/2)+1;
	 lst = new Img1duc[len];
	 
	 lst[0].New(2);
	 lst[0][0]=1;
	 lst[0][1]=1;
	 
	 lst[1].New(2);
	 lst[1][0]=0;
	 lst[1][1]=1;
	 
	 lst[2].New(4);
	 lst[2][0]=0;
	 lst[2][1]=1;
	 lst[2][2]=1;
	 lst[2][3]=1;
	 
	 cnt = 16;
	 idx = 2;
	 rad = 4;
	 int width=0; // width of the stored array at the previous iteration
	 int somme=0,a,b;
	 Img1duc tmp;
	 
	 while(cnt < H)
	    {
	       old = cnt;
	       
	       width = lst[idx].Width();
	       tmp.New(width);
	       tmp = lst[idx];
	       lst[idx].Delete();
	       lst[idx].New(width+2);

	       for (int i=0; i<width; i++)
		  lst[idx][i]=tmp[i];
	       lst[idx][width]=1;
	       lst[idx][width+1]=1;

	       cnt += 2*rad;
	       idx ++;
	       rad *= 2;
	       trg = min(4*old, H);
	  
	       a = cnt/rad;
	       b = (trg-cnt)/rad;
	       somme =  a + b;

	       lst[idx].New(somme);
	       for (int i=0; i<a; i++)
		  lst[idx][i]=0;
	       for (int i=a; i<somme; i++)
		  lst[idx][i]=1;
	
	       cnt = trg;
		
	    }
      }
      
      else
      if(pat == 'q') // Parabolic scaling by Laurent
	 {
	    len = (int) floor(log2((double)H)/2)+1;    
	    lst = new Img1duc[len];
	 
	    lst[0].New(2);
	    lst[0][0]=1;
	    lst[0][1]=1;

	    lst[1].New(4);
	    lst[1][0]=0;
	    lst[1][1]=1;
	    lst[1][2]=1;
	    lst[1][3]=1;

	    cnt = 8;
	    idx = 1;
	    rad = 2;
	    int width=0; // width of the stored array at the previous iteration
	    int somme=0,a,b;
	    Img1duc tmp;
	    
	    while(cnt < H)
	       {
		  old = cnt;
		  
		  width = lst[idx].Width();
		  tmp.New(width);
		  tmp = lst[idx];
		  lst[idx].Delete();
		  lst[idx].New(width+2);

		  for (int i=0; i<width; i++)
		  lst[idx][i]=tmp[i];
		  lst[idx][width]=1;
		  lst[idx][width+1]=1;

		  cnt += 2*rad;
		  idx ++;
		  rad *= 2;
		  trg = min(4*old, H);
	  
		  a = cnt/rad;
		  b = (trg-cnt)/rad;
		  somme =  a + b;

		  lst[idx].New(somme);
		  for (int i=0; i<a; i++)
		     lst[idx][i]=0;
		  for (int i=a; i<somme; i++)
		     lst[idx][i]=1;

		  cnt = trg;
	       }
	 }

   
   return SUCCESS;
}

/**
 * Function freq_pat
 * @param H : half length of the frequency span.
 *            H needs to be greater than 16
 * @param pat : type of frequency partition which satisfies parabolic scaling relationship
 *              equal to 'p' or 'q'
 * @output lst: A collection containing the frequency partition
 *
 * generate frequency partition
 */
Errc Freq_pat(Collection& lst, int H, char pat) {

   if (H<16) cerr<<"H needs to be at least 16"<<endl;

   int len, cnt, idx, rad, old, trg;
 
   if (pat == 'p')// Parabolic scaling by Lexing
      {
	 len = (int) ceil(log2((double)H)/2)+1;
	     
	 //Remplissage de la collection
	 Img1dsl *tmp;
	 Img1dsl *tmp2;
      
	 tmp = new Img1dsl;
	 tmp->New(2);
	 (*tmp)[0]=1;
	 (*tmp)[1]=1;
	 lst.SETPOBJECT("packets1", Img1dsl, (Img1dsl*)(tmp->Clone()));
	 
	 tmp = new Img1dsl;
	 tmp->New(2);
	 (*tmp)[0]=0;
	 (*tmp)[1]=1;
	 lst.SETPOBJECT("packets2", Img1dsl, (Img1dsl*)(tmp->Clone()));

	 tmp = new Img1dsl;
	 tmp->New(4);
	 (*tmp)[0]=0;
	 (*tmp)[1]=1;
	 (*tmp)[2]=1;
	 (*tmp)[3]=1;
	 lst.SETPOBJECT("packets3", Img1dsl, (Img1dsl*)(tmp->Clone()));

	 cnt = 16;
	 idx = 3;
	 rad = 4;
	 int width=0; // width of the stored array at the previous iteration
	 int somme=0,a,b;

	 char str[100];

	 while(cnt < H)
	    {
	       width = tmp->Width();
	       old = cnt;

	       tmp2 = new Img1dsl;
	       tmp2->New(width+2);

	       for (int i=0; i<width; i++)
		  (*tmp2)[i]=tmp[0][i];
	       (*tmp2)[width]=1;
	       (*tmp2)[width+1]=1;

	       sprintf(str, "packets%d", idx);
	       lst.SETPOBJECT(str, Img1dsl, (Img1dsl*)(tmp2->Clone()));
	       cnt += 2*rad;
	       idx ++;
	       rad *= 2;
	       trg = min(4*old, H);
	  
	       a = cnt/rad;
	       b = (trg-cnt)/rad;
	       somme =  a + b;

	       tmp2 = new Img1dsl;
	       tmp2->New(somme);
	       for (int i=0; i<a; i++)
		  (*tmp2)[i]=0;
	       for (int i=a; i<somme; i++)
		  (*tmp2)[i]=1;

	       sprintf(str, "packets%d", idx);
	       lst.SETPOBJECT(str, Img1dsl, (Img1dsl*)(tmp2->Clone()));
	       cnt = trg;
	       tmp=tmp2;
	    }
	 lst.SETVALUE("nb_scales", Ulong, (Ulong)idx);
      }

   else
      if(pat == 'q') // Parabolic scaling by Laurent
	 {
	    len = (int) floor(log2((double)H)/2)+1;    
	  
	    //Filling the collection
	    Img1dsl *tmp;
	    Img1dsl *tmp2;
      
	    tmp = new Img1dsl;
	    tmp->New(2);
	    (*tmp)[0]=1;
	    (*tmp)[1]=1;
	    lst.SETPOBJECT("packets1", Img1dsl, (Img1dsl*)(tmp->Clone()));
      
	    tmp = new Img1dsl;
	    tmp->New(4);
	    (*tmp)[0]=0;
	    (*tmp)[1]=1;
	    (*tmp)[2]=1;
	    (*tmp)[3]=1;
	    lst.SETPOBJECT("packets2", Img1dsl, (Img1dsl*)(tmp->Clone()));

	    cnt = 8;
	    idx = 2;
	    rad = 2;
	    int width=0; // width of the stored array at the previous iteration
	    int somme=0,a,b;

	    char str[100];

	    while(cnt < H)
	       {
		  width = tmp->Width();
		  old = cnt;

		  tmp2 = new Img1dsl;
		  tmp2->New(width+2);

		  for (int i=0; i<width; i++)
		     (*tmp2)[i]=(*tmp)[i];
		  (*tmp2)[width]=1;
		  (*tmp2)[width+1]=1;

		  sprintf(str, "packets%d", idx);
		  lst.SETPOBJECT(str, Img1dsl, (Img1dsl*)(tmp2->Clone()));

		  cnt += 2*rad;
		  idx ++;
		  rad *= 2;
		  trg = min(4*old, H);
	  
		  a = cnt/rad;
		  b = (trg-cnt)/rad;
		  somme =  a + b;

		  tmp2 = new Img1dsl;
		  (*tmp2).New(somme);
		  for (int i=0; i<a; i++)
		     (*tmp2)[i]=0;
		  for (int i=a; i<somme; i++)
		     (*tmp2)[i]=1;

		  sprintf(str, "packets%d", idx);
		  lst.SETPOBJECT(str, Img1dsl, (Img1dsl*)(tmp2->Clone()));

		  cnt = trg;
		  tmp=tmp2;
	       }
	    lst.SETVALUE("nb_scales", Ulong, (Ulong)idx);
	 }
   return SUCCESS;
}


#ifdef MAIN

#define USAGE   "usage: %s H(>=16) pat (p or q) [im_out|-]"
#define PARC    2
#define FINC    0
#define FOUTC   1
#define MASK    0

int main(int argc,char* argv[]) {
  Errc result;			// The result code of the execution.
  Pobject *mask;		// The mask.
  Pobject *objin[FINC+1];	// The input objects;
  Pobject *objs[FINC+1];	// The source objects masked by mask.
  Pobject *objout[FOUTC+1];	// The output object unmasked by mask.
  Pobject *objd[FOUTC+1];	// The result object.
  char *parv[PARC+1];		// The input parameters.
  
  ReadArgs(argc,argv,PARC,FINC,FOUTC,&mask,objin,objs,objout,objd,parv,USAGE,MASK);

  objd[0] = new Collection();

  Collection* imd = (Collection*) objd[0];

  result=Freq_pat(*imd, atoi(parv[0]),parv[1][0]);

  if (result)
    WriteArgs(argc,argv,PARC,FINC,FOUTC,&mask,objin,objs,objout,objd,MASK);
  Exit(result);
  return 0;
}

#endif
