/****************************************************************************
 *                                                                          *
 *     Loki - Programs for genetic analysis of complex traits using MCMC    *
 *                                                                          *
 *             Simon Heath - Rockefeller University                         *
 *                                                                          *
 *                       October 1997                                       *
 *                                                                          *
 * loki_init.c:                                                             *
 *                                                                          *
 * Copyright (C) Simon C. Heath 1997, 2000, 2002                            *
 * This is free software.  You can distribute it and/or modify it           *
 * under the terms of the Modified BSD license, see the file COPYING        *
 *                                                                          *
 ****************************************************************************/

#include <config.h>
#include <stdlib.h>
#include <string.h>
#ifdef USE_DMALLOC
#include <dmalloc.h>
#endif
#include <math.h>
#include <stdio.h>
#include <float.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include "ranlib.h"

#include "utils.h"
#include "loki.h"
#include "loki_peel.h"
#include "loki_output.h"
#include "loki_ibd.h"
#include "mat_utils.h"
#include "sample_rand.h"

#ifdef FUNC_NAME
#undef FUNC_NAME
#endif
#define FUNC_NAME "InitValues"
void InitValues(int *si_mode)
{
	int i,j,k,k1,type,n,mod,n_rec,*tmp;
	double y,s,mu;
	struct id_data *data;
	struct Id_Record *id;
	size_t size;
	
	if(syst_var[SYST_NO_OVERDOMINANT].flag && syst_var[SYST_NO_OVERDOMINANT].data.value) no_overdominant=1;
	if(syst_var[SYST_TAU_MODE].flag) {
		if(syst_var[SYST_TAU_MODE].flag==ST_REAL) tau_mode=(int)syst_var[SYST_TAU_MODE].data.rvalue;
		else tau_mode=syst_var[SYST_TAU_MODE].data.value;
	}
	if(syst_var[SYST_CENSOR_MODE].flag && syst_var[SYST_CENSOR_MODE].data.value) censor_mode=1;
	for(mod=0;mod<n_models;mod++) {
		type=models[mod].var.type;
		j=models[mod].var.var_index;
		n=0;
		s=mu=0.0;
		if(!(type&ST_FACTOR)) {
			id=id_array;
			for(i=0;i<ped_size;i++,id++) {
				if(polygenic_flag) id->bv[mod]=id->bvsum[mod]=id->bvsum2[mod]=0.0;
				if(type&ST_CONSTANT) id->n_rec=id->data?1:0;
				n_rec=id->n_rec;
				for(k1=k=0;k<n_rec;k++) {
					data=(type&ST_CONSTANT)?id->data+j:id->data1[k]+j;
					if(data && data->flag) {
						if(data->flag&ST_INTTYPE) y=(double)data->data.value;
						else y=data->data.rvalue;
						mu+=y;
						n++;
						k1++;
					}
				}
				if(!k1) id->res[mod]=0;
			}
			if(n) {
				if(grand_mean_set[mod]) mu=grand_mean[mod];
				else mu/=(double)n;
				id=id_array;
				for(i=0;i<ped_size;i++,id++) if(id->res[mod]) {
					if(type&ST_CONSTANT) n_rec=id->data?1:0;
					else n_rec=id->n_rec;
					for(k=0;k<n_rec;k++) {
						data=(type&ST_CONSTANT)?id->data+j:id->data1[k]+j;
						if(data && data->flag&ST_INTTYPE) y=(double)data->data.value;
						else y=data->data.rvalue;
						y-=mu;
						s+=y*y;
						id->res[mod][k]=y;
						if(use_student_t) id->vv[mod][k]=1.0;
						if((type&ST_CENSORED)&&(data->flag&2)) {
							id->cens[mod][k]=0.0;
							censored_flag=1;
						}
					}
				}
			}
			if(!res_var_set[mod]) {
				s=n?s/(double)n:1.0;
				if(s<residual_var_limit[mod]) s=residual_var_limit[mod];
				BB(residual_var,mod,mod)=s;
			} else if(BB(residual_var,mod,mod)<residual_var_limit[mod]) {
				BB(residual_var,mod,mod)=residual_var_limit[mod];
				(void)fprintf(stderr,"Warning - residual variance for model %d reset to limit (%g)\n",mod+1,residual_var_limit[mod]);
			}
			if(!add_var_set[mod]) {
				BB(additive_var,mod,mod)=BB(residual_var,mod,mod);
				if(BB(additive_var,mod,mod)<additive_var_limit[mod]) BB(additive_var,mod,mod)=additive_var_limit[mod];
			} else if(additive_var[mod]<additive_var_limit[mod]) {
				additive_var[mod]=additive_var_limit[mod];
				(void)fprintf(stderr,"Warning - additive variance for model %d reset to limit (%g)\n",mod+1,additive_var_limit[mod]);
			}
		}
		if(!grand_mean_set[mod]) grand_mean[mod]=mu;
		if(syst_var[SYST_TAU].flag) {
			if(syst_var[SYST_TAU].flag==ST_REAL) tau_beta[0]=syst_var[SYST_TAU].data.rvalue;
			else tau_beta[mod]=(double)syst_var[SYST_TAU].data.value;
		} else if(tau_mode==1) tau_beta[mod]=residual_var[mod];
		switch(tau_mode) {
		 case 0:
			tau_beta[mod]*=residual_var[mod];
		 case 1:
			tau[mod]=tau_beta[mod];
			break;
		 case 2:
			tau[mod]=residual_var[mod]*tau_beta[mod];
			break;
		}
	}
	if(syst_var[SYST_IBD_OUTPUT].flag) {
		if(syst_var[SYST_IBD_OUTPUT].flag==ST_REAL) *ibd_mode=(int)syst_var[SYST_IBD_OUTPUT].data.rvalue;
		else *ibd_mode=syst_var[SYST_IBD_OUTPUT].data.value;
	}
	if(n_markers>1 && ((*ibd_mode)&IBD_SINGLE_POINT)) { /* Set up singlepoint IBD analysis */
		if(analysis&ESTIMATE_IBD) { /* Set up singlepoint IBD analysis */
			if(!(tmp=malloc(sizeof(int)*n_markers))) ABT_FUNC(MMsg);
			for(i=0;i<n_markers;i++) {
				j=marker[i].locus.link_group;
				tmp[i]=linkage[j].type;
			}
			if(linkage) {
				for(i=0;i<n_links;i++) {
					if(linkage[i].ibd_list) {
						free(linkage[i].ibd_list->pos);
						free(linkage[i].ibd_list);
					}
				}
				free(linkage);
			}
			if(!(linkage=malloc(sizeof(struct Link)*n_markers))) ABT_FUNC(MMsg);
			n_links=n_markers;
			for(i=0;i<n_markers;i++) {
				if(!(marker[i].index)) linkage[i].name=marker[i].name;
				else {
					size=strlen(marker[i].name)+10;
					if(!(linkage[i].name=malloc(size))) ABT_FUNC(MMsg);
					RemBlock=AddRemem(linkage[i].name,RemBlock);
					(void)sprintf(linkage[i].name,"%s(%d)",marker[i].name,marker[i].index);
				}
				for(j=0;j<2;j++) linkage[i].r1[j]=linkage[i].r2[j]=0.0;
				linkage[i].n_markers=1;
				linkage[i].type=tmp[i];
				linkage[i].ibd_list=0;
				linkage[i].sample_pos=0;
				linkage[i].range_set[0]=linkage[i].range_set[1]=0;
				linkage[i].ibd_est_type=IBD_EST_MARKERS;
				marker[i].locus.link_group=i;
			}
			free(tmp);
		}
	}
	if(syst_var[SYST_SI_MODE].flag) {
		if(syst_var[SYST_SI_MODE].flag==ST_REAL) *si_mode=(int)syst_var[SYST_SI_MODE].data.rvalue;
		else *si_mode=syst_var[SYST_SI_MODE].data.value;
	}
	if(syst_var[SYST_RNG].flag) {
		if(syst_var[SYST_RNG].flag==ST_REAL) i=(int)syst_var[SYST_RNG].data.rvalue;
		else i=syst_var[SYST_RNG].data.value;
		if(set_mt_idx(i)<0) {
			fprintf(stderr,"Invalid RNG (%d) selected - using default generator\n",i);
		}
	}
	if(syst_var[SYST_GENV_OUT].flag && syst_var[SYST_GENV_OUT].data.value) genv_out=1; /* EWD */
#ifdef DEBUG
	if(syst_var[SYST_DEBUG_LEVEL].flag)	{
		if(syst_var[SYST_DEBUG_LEVEL].flag==ST_REAL) (*debug_level)=(int)syst_var[SYST_DEBUG_LEVEL].data.rvalue;
		else (*debug_level)=syst_var[SYST_DEBUG_LEVEL].data.value;
	}
#endif
#ifdef TRACE_PEEL
	if(syst_var[SYST_PEEL_TRACE].flag) {
		if(syst_var[SYST_PEEL_TRACE].flag==ST_REAL) *peel_trace=(int)syst_var[SYST_PEEL_TRACE].data.rvalue;
		else *peel_trace=syst_var[SYST_PEEL_TRACE].data.value;
	}
#endif
	if(syst_var[SYST_LM_RATIO].flag)	{
		if(syst_var[SYST_LM_RATIO].flag==ST_REAL) lm_ratio=syst_var[SYST_LM_RATIO].data.rvalue;
		else lm_ratio=(double)syst_var[SYST_LM_RATIO].data.value;
	}
	for(i=0;i<N_MOVE_STATS;i++) move_stats[i].success=move_stats[i].n=0;
	init_rand();
}
