//Sample size calculations online. For two means, considering 
//statistical power and alpha levels, usefull for analysis of 
//randomized trials (RCT)
//copyright: Daan G Uitenbroek PhD

function addspace(real,lenght) 
{
var str=""+real;
for (var index=str.length;index<=lenght;index++)
      str=" "+str;
var pt=str.indexOf(".");
if (pt==0) str="0"+str    //solves that newer versions of Netscape give inconsistent numeric notations
return str;
}

function array(len)
{
  this.length=len;
   for (var i=1;i<=len;i++)
      this[i]=0;
  return this
}

function alloratio(p1,p2,type)  //calculates the optimum allocation ratio
{
writeln="\n";
if (navigator.appVersion.lastIndexOf('Win') != -1) writeln="\r\n";

if (type<2)
var theta=Math.sqrt((p2*(1-p2))/(p1*(1-p1)))
else
var theta=Math.sqrt((p2*p2)/(p1*p1))

theta=Math.round(theta*100)/100
return theta
}

function numofcases(p1,p2,std1,std2,alfa,beta,alloc,checkbox)
{
writeln="\n";
if (navigator.appVersion.lastIndexOf('Win') != -1) writeln="\r\n";

var delta=Math.abs(p1-p2);
if (std1==0)
{
   var phat=(1*p1+alloc*p2)/(1*1+1*alloc);
   var n=(alfa*Math.sqrt((1*1+alloc*1)*phat*(1-phat))+(beta*Math.sqrt((alloc*((p1*(1-p1)))+(p2*(1-p2))))))/delta;
   n=n*n/alloc;   //n without continuity correction
   if (checkbox.checked)         //adds continuity correction
       n=(n/4)*(1*1+(Math.sqrt(1*1+((2*(1*1+alloc*1))/(alloc*n*delta)))))*(1*1+(Math.sqrt(1*1+((2*(1*1+alloc*1))/(alloc*n*delta)))))  
var outp=n
}
else
{ 
   if (std2!=0) std1=(std1*1+std2*1)/2
   delta=(delta/std1)*(delta/std1);
    var n=(2*(alfa*1+beta*1)*(alfa*1+beta*1)/delta)*1    //crude n
  if (checkbox.checked)        //for n with continuity correction
       n=n*1+(alfa*alfa/4)*1
    var outp=((alloc*1+1*1)*n)/(2*alloc)
}
return outp        
}

function eqnum(p1,p2,toll,alfa,beta,std,alloc)
{
if (std==0)
{
var denom=((alfa*1+beta*1)/(toll*1-Math.abs(p1*1-p2*1))) 
denom=denom*denom                                              //square
var outp=((alloc*p1*(1-p1))+(p2*(1-p2)))*denom/alloc
} else
{
var denom=std*(alfa*1+beta*1)/(Math.abs(p2*1-p1*1)-toll*1) //
denom=denom*denom                                              //square
var outp=(1+alloc*1)*denom/alloc
}
return outp      
}

function pairw (p1,p2,std1,alfa,beta,checkbox,alloc)
{
writeln="\n";
if (navigator.appVersion.lastIndexOf('Win') != -1) writeln="\r\n";


document.form1.outp.value+=writeln+"p1= "+p1+" p2= "+p2+" std1= " +std1+" alloc= "+alloc

if (std1==0) 
{
if (checkbox.checked)
 {var pp1=(p1*(1-p2*1))
  var pp2=(p2*(1-p1*1))}
  else
 {var pp1=p1
  var pp2=p2}

var ratio=(pp1/pp2)
var piedisc=(pp1*1+pp2*1)

var denom=(alfa*(ratio+1*1))*1+1*(beta*Math.sqrt(((ratio+1*1)*(ratio+1*1))-((ratio-1)*(ratio-1)*piedisc)));
denom=denom*denom;
var numer=(ratio-1*1)*(ratio-1*1)*piedisc
var outp=denom/numer
}

else

{var delta=(p1/std1)*(p1/std1);
 var n=((alfa*1+beta*1)*(alfa*1+beta*1)/delta)*1    //crude n
 if (checkbox.checked) {var outp=n}
    else {var outp=n*1+(alfa*alfa/2)*1}
}
return outp
}

function popul(pp1,pp2,sd1,sd2,alfa,beta,checkbox)
{
writeln="\n";
if (navigator.appVersion.lastIndexOf('Win') != -1) writeln="\r\n";

var delta=Math.abs(pp1-pp2);
if (((sd1==0) & (sd2==0)) & (pp1>0.0001)) 
{
   var n=(alfa*Math.sqrt(pp1*(1-pp1))+(beta*Math.sqrt(pp2*(1-pp2))))/delta;
   n=n*n;   //n without continuity correction
   if (checkbox.checked)         //adds continuity correction
       n=(n/4)*(1*1+(Math.sqrt(1*1+(4/(n*delta))))*(1*1+(Math.sqrt(1*1+(4/(n*delta)))))) 
   var outp=n
}
else
{
   if (sd1==0) sd1=sd2*1
   delta=(delta/sd1)*(delta/sd1);
   var n=((alfa*1+beta*1)*(alfa*1+beta*1)/delta)*1    //crude n
   if (sd2>0) {n=n*1+(alfa*alfa/2)*1}
var outp=n   
}
return outp
}

function samplesize(p1,p2,std1,std2,alloc,type,checkbox) //main procedure
{
writeln="\n";
if (navigator.appVersion.lastIndexOf('Win') != -1) writeln="\r\n";

peas=new array(10);
tail=new array(10);
betaas=new array(5);

peas[1]=1.283; //start blok for double sided
tail[1]=0.20;
peas[2]=1.645; 
tail[2]=0.10;
peas[3]=1.960;
tail[3]=0.05;
peas[4]=2.576;
tail[4]=0.01;
peas[5]=3.291;
tail[5]=0.001;
peas[6]=0.847; //start blok for single sided
tail[6]=0.20;
peas[7]=1.282; 
tail[7]=0.10;
peas[8]=1.645;
tail[8]=0.05;
peas[9]=2.326;
tail[9]=0.01;
peas[10]=3.090;
tail[10]=0.001;
betaas[1]=0.252;  //power 60%
betaas[2]=0.522;  //power 70%
betaas[3]=0.847;  //power 80%
betaas[4]=1.282;  //power 90%
betaas[5]=1.645;  //power 95%

var typecorrect=0

if (type==2)
{
if (p2==0) p2=p1
document.form1.outp.value+="\t   EQUALITY ANALYSIS"+writeln
typecorrect=1
}
if (type==3) document.form1.outp.value+="\t   POPULATION ANALYSIS"+writeln
if (type==4) document.form1.outp.value+="\t   PAIRWISE ANALYSIS"+writeln

document.form1.outp.value+="\tRESULTS for double sided"+writeln
document.form1.outp.value+="alpha\t\t  power"+writeln

if (type!=2)
document.form1.outp.value+="\t 0.6\t 0.7\t 0.8\t 0.9"+writeln;
else
document.form1.outp.value+="\t 0.7\t 0.8\t 0.9\t 0.95"+writeln;

if ((p1<1)|(p2<1))   // prepares the analysis
  if ((p2>1)|(p1>1))  
     document.form1.outp.value+=
         "WARNING one average is a proportion other one is a number"+writeln;

if ((type!=2)&((p1>=1)&(std1==0))&(type!=4)&(type!=3)) //work out the standardeviations in this block
{
std1=Math.sqrt(p1)
document.form1.outp.value+=
     "WARNING average one presumed Poisson distributed"+writeln;
if (std2==0) {std2=Math.sqrt(p2)
     document.form1.outp.value+=
         "WARNING average two presumed Poisson distributed"+writeln;}
}
if ((type==2)&(p1>=1)&(std2==0)) std2=Math.sqrt(p1+p2)

document.form1.outp.value+="------------------------------------------------"+writeln;

// end of preperation start of calculations

for (var index=2;index<=5;index++)  //this for statement does clasical model
   {str=""+tail[index-typecorrect]
    pt=str.indexOf(".");
    if (pt==0) str="0"+str    //solves that newer versions of Netscape give inconsistent numeric notations
    document.form1.outp.value+=str
    for (var jndex=1;jndex<=4;jndex++)               
        {document.form1.outp.value+="\t"          
          if (type==1) document.form1.outp.value+=
            addspace(Math.round(numofcases(p1,p2,std1,std2,peas[index],betaas[jndex],alloc,checkbox)+0.5*1),4);
          if (type==2) document.form1.outp.value+=
            addspace(Math.round(eqnum(p1,p2,std1,peas[index-1],betaas[jndex+1],std2,alloc)+0.5*1),4);
          if (type==3) document.form1.outp.value+=
             addspace(Math.round(popul(p1,p2,std1,std2,peas[index],betaas[jndex],checkbox)+0.5*1),4)
          if (type==4) document.form1.outp.value+=
            addspace(Math.round(pairw(p1,p2,std1,peas[index],betaas[jndex],checkbox,alloc)+0.5*1),4)}
   document.form1.outp.value+=writeln;
   }
if ((type==3) & (std1==0) & (p1<=0.01))
    document.form1.outp.value+=writeln+"WARNING, a conservative estimate is used"+writeln
document.form1.outp.value+=writeln;       //end of double sided output

if (type==2) document.form1.outp.value+="\t   EQUALITY ANALYSIS"+writeln
if (type==3) document.form1.outp.value+="\t   POPULATION ANALYSIS"+writeln
if (type==4) document.form1.outp.value+="\t   PAIRWISE ANALYSIS"+writeln

document.form1.outp.value+="\tRESULTS for single sided"+writeln
document.form1.outp.value+="alpha\t\t  power"+writeln;

if (type!=2)
document.form1.outp.value+="\t 0.6\t 0.7\t 0.8\t 0.9"+writeln;
else
document.form1.outp.value+="\t 0.7\t 0.8\t 0.9\t 0.95"+writeln;

document.form1.outp.value+="------------------------------------------------"+writeln;

for (var index=7;index<=10;index++)
   {str=""+tail[index-typecorrect]
     pt=str.indexOf(".");
     if (pt==0) str="0"+str    //solves that newer versions of Netscape give inconsistent numeric notations
    document.form1.outp.value+=str
    for (var jndex=1;jndex<=4;jndex++)               
        {document.form1.outp.value+="\t"          
          if (type==1) document.form1.outp.value+=
            addspace(Math.round(numofcases(p1,p2,std1,std2,peas[index],betaas[jndex],alloc,checkbox)+0.5*1),4);
          if (type==2) document.form1.outp.value+=
            addspace(Math.round(eqnum(p1,p2,std1,peas[index-1],betaas[jndex+1],std2,alloc)+0.5*1),4);
          if (type==3) document.form1.outp.value+=
             addspace(Math.round(popul(p1,p2,std1,std2,peas[index],betaas[jndex],checkbox)+0.5*1),4)
          if (type==4) document.form1.outp.value+=
            addspace(Math.round(pairw(p1,p2,std1,peas[index],betaas[jndex],checkbox,alloc)+0.5*1),4);}
        document.form1.outp.value+=writeln;
   }
if ((type==3) & (std1==0) & (p1<=0.01))
    document.form1.outp.value+=writeln+"WARNING, a conservative estimate is used"
if ((type==1) & (p1<1))
    document.form1.outp.value+=writeln+"optimum allocation ratio equals: "+addspace(alloratio(p1,p2,1),4)
if ((type==1) & (p1>=1))
    document.form1.outp.value+=writeln+"optimum allocation ratio equals: "+addspace(alloratio(std1,std2,3),4)
document.form1.outp.value+=writeln;   //end of single sided output

}

function ClearOutp()
{
var writeln="\n";
if (navigator.appVersion.lastIndexOf('Win') != -1) writeln="\r\n"; 
document.form1.outp.value ="cleared"+writeln;
}

