#include <string.h>
#include <math.h>
#include "matched.h"
#include "file.h"
#include "verification.h"
#include "treematch.h"
#include "opm_param.h"

struct _matched {
   int id1, id2, flag;
   double x1, y1, x1org, y1org, m1, x2, y2, m2;
};

static matched make_new_matched(char *line);
static void check_matched_null(matched p, char *func);
static Boolean scan_coef(char *line, char *keyword, double *coef);
static int double_cmp(const void *x1, const void *x2);

int output_matched_result(FILE *flog, char *output, int nobj, xym *data_obj, int nref, xym *data_ref, double *coef, opm_param *setting){
   FILE *fp;
   int i, num, num1, flag;
   double radius, xcen, ycen, size;
   Leaf *ref, *obj, target;
   struct _matched match;
   xym p, q;
   fp=fileopen(output,"w");
   radius=get_opm_radius(setting);
   xcen=get_opm_xcen(setting);
   ycen=get_opm_ycen(setting);
   size=get_opm_size(setting);
   print_opm_param(fp,setting);
   print_output_coef(fp,coef);
   obj=make_leaf(nobj,data_obj);
   ref=make_leaf(nref,data_ref);
   make_treematch(nobj,obj,nref,ref,xcen,ycen,size,radius);
   for(i=0,num=0,num1=0;i<nref;i++){
      if((target=ref[i]->adopted)==NULL) continue;
      p=(xym)(ref[i]->data);
      q=(xym)(target->data);
      if(ref[i]->nmatch==1&&target->nmatch==1) flag=MATCHED_SINGLE;
      else { flag=MATCHED_MULTI; ++num1; }
      //flag=0;
      xym_to_matched(q,p,flag,&match);
      print_matched(fp,&match);
      ++num;
   }
   if(flog!=NULL){
      fprintf(flog,"# %d matches found (nobj=%d nref=%d).\n",num,nobj,nref);
      fprintf(flog,"#     flag=%d: %d,   flag=%d: %d\n",MATCHED_SINGLE,(num-num1),MATCHED_MULTI,num1);
   }
   fclose(fp);
   for(i=0;i<nobj;i++) free(obj[i]);
   for(i=0;i<nref;i++) free(ref[i]);
   free(obj); free(ref);
   return num;
}

void print_output_coef(FILE *fp, double *coef){
   fprintf(fp,"#  xref = %12.5e xobj + %12.5e yobj + %12.5e\n",coef[0],coef[1],coef[2]);
   fprintf(fp,"#  yref = %12.5e xobj + %12.5e yobj + %12.5e\n",coef[3],coef[4],coef[5]);
//   fprintf(fp,"#  xref = %12.5f xobj + %12.5f yobj + %12.5f\n",coef[0],coef[1],coef[2]);
//   fprintf(fp,"#  yref = %12.5f xobj + %12.5f yobj + %12.5f\n",coef[3],coef[4],coef[5]);
}

void xym_to_matched(xym obj, xym ref, int flag, matched p){
   p->id1=get_xym_id(obj);
   p->x1org=get_xym_xorg(obj); p->y1org=get_xym_yorg(obj);
   p->x1=get_xym_x(obj); p->y1=get_xym_y(obj); p->m1=get_xym_morg(obj);
   p->id2=get_xym_id(ref); p->x2=get_xym_xorg(ref); p->y2=get_xym_yorg(ref);
   p->m2=get_xym_morg(ref);
   p->flag=flag;
}

void print_matched(FILE *fp, matched p){
   fprintf(fp,MATCHED_FORMAT_OUT,p->id1,p->x1org,p->y1org,p->x1,p->y1,p->m1,p->id2,p->x2,p->y2,p->m2,p->flag);
}

matched *load_matched(char *file, int *ndata){
   FILE *fp;
   matched *p;
   int i, nline, num;
   char line[LINE_LENGTH];
   if((nline=file_nline(file))<=0) return NULL;
   p=malloc(nline*sizeof(matched));
   for(i=0;i<nline;i++) p[i]=NULL;
   num=0;
   fp=fileopen(file,"r");
   while(!feof(fp)){
      fgets(line,sizeof(line),fp);
      if(comment_line(line)==TRUE||feof(fp)) continue;
      if((p[num]=make_new_matched(line))!=NULL) ++num;
   }
   if(num<=0){ free(p); p=NULL; return NULL; }
   *ndata=num;
   fclose(fp);
   return p;
}

static matched make_new_matched(char *line){
   matched p;
   int id1, id2, flag;
   double x1, y1, x1org, y1org, m1, x2, y2, m2;
   if(sscanf(line,MATCHED_FORMAT_IN,&id1,&x1org,&y1org,&x1,&y1,&m1,&id2,&x2,&y2,&m2,&flag)!=11) return NULL;
   p=malloc_matched();
   p->id1=id1; p->x1=x1; p->y1=y1; p->x1org=x1org; p->y1org=y1org; p->m1=m1;
   p->id2=id2; p->x2=x2; p->y2=y2; p->m2=m2; p->flag=flag;
   return p;
}

matched malloc_matched(void){
   matched p;
   if((p=malloc(sizeof(struct _matched)))==NULL){
      fprintf(stderr,"!!! malloc_matched failed !!!\n"); exit(1);
   }
   return p;
}

void destroy_matched(int ndata, matched *data){
   int i;  
   for(i=0;i<ndata;i++) free(data[i]);
   free(data); data=NULL;
}

int get_matched_id1(matched p){
   check_matched_null(p,"get_matched_id1");
   return (p->id1);
}

double get_matched_x1(matched p){
   check_matched_null(p,"get_matched_x1");
   return (p->x1);
}

double get_matched_y1(matched p){
   check_matched_null(p,"get_matched_y1");
   return (p->y1);
}

double get_matched_x1org(matched p){
   check_matched_null(p,"get_matched_x1org");
   return (p->x1org);
}

double get_matched_y1org(matched p){
   check_matched_null(p,"get_matched_y1org");
   return (p->y1org);
}

double get_matched_m1(matched p){
   check_matched_null(p,"get_matched_m1");
   return (p->m1);
}

int get_matched_id2(matched p){
   check_matched_null(p,"get_matched_id2");
   return (p->id2);
}

double get_matched_x2(matched p){
   check_matched_null(p,"get_matched_x2");
   return (p->x2);
}

double get_matched_y2(matched p){
   check_matched_null(p,"get_matched_y2");
   return (p->y2);
}

double get_matched_m2(matched p){
   check_matched_null(p,"get_matched_m2");
   return (p->m2);
}

int get_matched_flag(matched p){
   check_matched_null(p,"get_matched_flag");
   return (p->flag);
}

static void check_matched_null(matched p, char *func){
   if(p==NULL){
      fprintf(stderr,"Null matched was given in %s\n",func); exit(1);
   }
}

Boolean read_matched_coef(char *file, double *coef){
   int i;
   FILE *fp;
   double tmp[6]={ 0, 0, 0, 0, 0, 0 };
   Boolean flag[2]={ FALSE, FALSE };
   char line[LINE_LENGTH];
   fp=fileopen(file,"r");
   while(!feof(fp)){
      fgets(line,sizeof(line),fp);
      if(comment_line(line)!=TRUE) continue;
      if(strstr(line,"xref")!=NULL&&flag[0]==FALSE) flag[0]=scan_coef(line,"xref",tmp);
      if(strstr(line,"yref")!=NULL&&flag[1]==FALSE) flag[1]=scan_coef(line,"yref",tmp+3);
   }
   fclose(fp);
   for(i=0;i<6;i++) coef[i]=tmp[i];
   if(flag[0]==TRUE&&flag[1]==TRUE) return TRUE;
   return FALSE;
}

static Boolean scan_coef(char *line, char *keyword, double *coef){
   int i;
   double tmp[3];
   char key[LINE_LENGTH];
   if(sscanf(line,"#  %s = %lf xobj + %lf yobj + %lf",key,tmp,tmp+1,tmp+2)!=4) return FALSE;
   if(strcmp(key,keyword)!=0) return FALSE;
   for(i=0;i<3;i++) coef[i]=tmp[i];
   return TRUE;
}

void get_refmag_delta(int ndata, matched *data, double *refmag, double *delta){
   int i;
   matched p;
   for(i=0;i<ndata;i++){
      p=data[i];
      refmag[i]=get_matched_m2(p);
      delta[i]=get_matched_m1(p)-refmag[i];
   }
}

void get_matched_dxdy(int ndata, matched *data, double *dx, double *dy){
   int i;
   for(i=0;i<ndata;i++){
      dx[i]=get_matched_x1(data[i])-get_matched_x2(data[i]);
      dy[i]=get_matched_y1(data[i])-get_matched_y2(data[i]);
   }
}

void get_matched_xy1org(int ndata, matched *data, double *x1org, double *y1org){
   int i;
   for(i=0;i<ndata;i++){
      x1org[i]=get_matched_x1org(data[i]);
      y1org[i]=get_matched_y1org(data[i]);
   }
}

void get_matched_xy1(int ndata, matched *data, double *x1, double *y1){
   int i;
   for(i=0;i<ndata;i++){
      x1[i]=get_matched_x1(data[i]);
      y1[i]=get_matched_y1(data[i]);
   }
}
void get_matched_xy2(int ndata, matched *data, double *x2, double *y2){
   int i;
   for(i=0;i<ndata;i++){
      x2[i]=get_matched_x2(data[i]);
      y2[i]=get_matched_y2(data[i]);
   }
}

double get_matched_magdelta(int ndata, matched *data){
   int i;
   double *x, tmp;
   extern int double_cmp(const void *x1, const void *x2);
   x=malloc(ndata*sizeof(double));
   for(i=0;i<ndata;i++) x[i]=get_matched_m1(data[i])-get_matched_m2(data[i]);
   qsort(x,ndata,sizeof(double),*double_cmp);
   tmp=x[ndata/2];
   free(x);
   return tmp;
}

static int double_cmp(const void *x1, const void *x2){
   double a, b;
   a=*(double *)x1;
   b=*(double *)x2;
   if(a>b) return 1;
   else if(a==b) return 0;
   return -1;
}

