/*
  (2006--2013) Thomas A. Gerds 
  --------------------------------------------------------------------
  distributed under the terms of the GNU public license 
  y the SORTED failure times with ties 
  status is 1 if the individual has failed (from any cause), 0 otherwise 
  cause indicates the cause
  caseweights are multiplied to the individual contributions to
  the numbers of events and the numbers at risk 
  N is the length of Y  
  NC is the number of different clusters 
  NS is the number of states (aka causes) 
  cluster indicates the cluster
  size is a vector with the number of individuals in strata
*/
	      
#include <math.h>
#include <R.h>
#include "prodlim.h"

void prodlimSRC(double *y,
		double *status,
		int *cause,
		double *entrytime,
		double *caseweights,
		int *cluster,
		int *N,
		int *NS,
		int *NC,
		int *NU,
		int *size,
		double *time,
		double *nrisk,
		double *event,
		double *lost,
		double *surv,
		double *risk,
		double *hazard,
		double *varhazard,
		double *extra_double,
		int *max_nc,
		int *ntimes,
		int *size_strata,
		int *first_strata,
		int *reverse,
		int *model,
		int *independent,
		int *delayed,
		int *weighted) {
  int t, u, start, stop, size_temp;
  t=0;
  start=0;
  size_temp=0;
  for (u=0;u<*NU;u++){
    stop=start+size[u];
    if (*model==0){
      if (*independent==1){
	if (*weighted==1 || *delayed==1){
	  prodlimSurvPlus(y,status,entrytime,caseweights,time,nrisk,event,lost,surv,hazard,varhazard,reverse,&t,start,stop,delayed,weighted);
	}
	else{
	  prodlim_surv(y,status,time,nrisk,event,lost,surv,hazard,varhazard,reverse,&t,start,stop);
	}
      }
      else{
	double *cluster_nrisk, *adj1, *adj2, *adjvarhazard;
	double *ncluster_lost, *ncluster_with_event, *sizeof_cluster, *nevent_in_cluster;
	/*
	  tag: 12 Nov 2010 (18:41)
	  
	the length of nrisk, nevent and lost is 2 * N
	the first half is used for the individual level
	the second for the cluster level.
	
	the function is thus still restricted to a single cluster variable
	*/
	cluster_nrisk = nrisk + *N;
	ncluster_with_event = event + *N;
	ncluster_lost = lost + *N;
	adjvarhazard = varhazard + *N;
	adj1 = extra_double;
	adj2 = extra_double + *max_nc;
	nevent_in_cluster = extra_double + *max_nc + *max_nc;
	sizeof_cluster = extra_double + *max_nc  + *max_nc + *max_nc;
	prodlim_clustersurv(y,status,cluster,NC + u,time,nrisk,cluster_nrisk,event,lost,ncluster_with_event,ncluster_lost,sizeof_cluster,nevent_in_cluster,surv,hazard,varhazard,adj1,adj2,adjvarhazard,&t,start,stop);
      }
    }
    else{
      if (*model==1){
	double *risk_temp, *risk_lag, *v1, *v2;
	risk_temp = extra_double;
	risk_lag = extra_double + *NS;
	v1 = extra_double + *NS + *NS;
	v2 = extra_double + *NS + *NS + *NS;
	if (*weighted==1 || *delayed==1){
	  prodlimCompriskPlus(y,status,cause,entrytime,caseweights,NS,time,nrisk,event,lost,surv,risk,hazard,varhazard,risk_temp,risk_lag,v1,v2,&t,start,stop,delayed,weighted);
	}
	else{
	  prodlim_comprisk(y,status,cause,NS,time,nrisk,event,lost,surv,risk,hazard,varhazard,risk_temp,risk_lag,v1,v2,&t,start,stop);
	}
      }
    }
    start+=size[u];
    size_strata[u] = t - size_temp;
    first_strata[u] = t + 1 - size_strata[u];
    size_temp += size_strata[u];
  }
  *ntimes=t;
}


void pl_step(double *pl,double *aj,double *v,double n,double d,int rev){
  if (d > 0){	     
    *aj = (d / (double) (n - rev));	/* nelson-aalen */
    *v += (double) d / ((double) (n - rev) * (double) (n - rev - d)); /* greenwood variance */
    *pl *= (1 - *aj); /* product limit */
  } else{
    *aj=0;
  }
}











