Changeset 1782


Ignore:
Timestamp:
Dec 12, 2012, 3:05:23 PM (7 years ago)
Author:
Nicklas Nordborg
Message:

Catching up on trunk revisions 1755 to 1781.

Location:
extensions/net.sf.basedb.reggie/branches/ticket-422
Files:
19 edited
1 copied

Legend:

Unmodified
Added
Removed
  • extensions/net.sf.basedb.reggie/branches/ticket-422

  • extensions/net.sf.basedb.reggie/branches/ticket-422/META-INF/extensions.xml

    r1769 r1782  
    77      and samples.
    88    </description>
    9     <version>2.10-dev</version>
     9    <version>2.11-dev</version>
    1010    <min-base-version>3.2.1</min-base-version>
    1111    <copyright>BASE development team</copyright>
  • extensions/net.sf.basedb.reggie/branches/ticket-422/README

    r1769 r1782  
    8484
    8585 * Histology wizards
    86    TODO
     86   Three wizards used in the process of creating H&E stained glass
     87   slides. The first wizard creates a printable lab tracking protocol
     88   for the current batch biomaterial items that are about to be
     89   processed. The second wizard records the paraffin embedding step,
     90   and the last wizard records the H&E staining step.
    8791
    8892 * RNA quality control wizards
  • extensions/net.sf.basedb.reggie/branches/ticket-422/build.xml

    r1769 r1782  
    1010  <!-- variables used -->
    1111  <property name="name" value="reggie" />
    12   <property name="version" value="2.10-dev" />
     12  <property name="version" value="2.11-dev" />
    1313  <property name="src" location="src" description="Location of source files" />
    1414  <property name="build" location="build" description="Location of compiled files" />
  • extensions/net.sf.basedb.reggie/branches/ticket-422/resources/bloodform.jsp

    r1726 r1782  
    7171    if (frm.allFirstNames.value == '')
    7272    {
    73       setInputStatus('allFirstNames', 'Missing', 'invalid');
    74       frm.allFirstNames.focus();
     73      setInputStatus('allFirstNames', 'Missing', 'warning');
    7574      formOk = false;
    7675    }
     
    8281    if (frm.familyName.value == '')
    8382    {
    84       setInputStatus('familyName', 'Missing', 'invalid');
    85       frm.familyName.focus();
     83      setInputStatus('familyName', 'Missing', 'warning');
    8684      formOk = false;
    8785    }
     
    104102  return formOk;
    105103}
     104
     105function step2IsAcceptable()
     106{
     107  var formOk = true;
     108  var frm = document.forms['reggie'];
     109  // New patient only
     110  if (!patientInfo.id)
     111  {
     112    formOk = frm.patientCode.value != '';
     113  }
     114  return formOk;
     115}
     116
    106117
    107118function step3IsValid()
     
    141152  else if (currentStep == 2)
    142153  {
    143     if (step2IsValid()) gotoStep3();
     154    if (step2IsValid())
     155    {
     156      gotoStep3();
     157    }
     158    else if (step2IsAcceptable())
     159    {
     160      if (manual)
     161      {
     162        gotoStep3();
     163      }
     164      else
     165      {
     166        setInnerHTML('gonext.message', 'Missing name(s). Click \'Next\' to continue registration.');
     167      }
     168    }
    144169  }
    145170}
     
    220245  setInputStatus('pnr', '', 'valid');
    221246  pnrIsValid = true;
     247}
     248
     249function nameOnChange(event)
     250{
     251  var field = event.target;
     252  if (field.value == '')
     253  {
     254    setInputStatus(field.name, 'Missing', 'warning');
     255  }
     256  else
     257  {
     258    setInputStatus(field.name, '', 'valid');
     259  }
    222260}
    223261
     
    435473      Forms.selectListOption(frm.bloodSample, bloodInfo.bloodSample);
    436474    }
     475    if (bloodInfo.otherPathNote)
     476    {
     477      frm.otherPathNote.value = bloodInfo.otherPathNote;
     478    }
    437479  }
    438480  else
     
    481523  bloodInfo.serum = frm.serum.checked ? "Yes" : "No";
    482524  bloodInfo.bloodSample = frm.bloodSample[frm.bloodSample.selectedIndex].value;
     525  bloodInfo.otherPathNote = frm.otherPathNote.value;
    483526  if (frm.copyConsent.checked && frm.copyConsent.value)
    484527  {
     
    491534  frm.freezerTime.disabled = true;
    492535  frm.bloodSample.disabled = true;
     536  frm.otherPathNote.disabled = true;
    493537
    494538  var updateMode = bloodInfo.id;
     
    601645        <td class="prompt">Family name</td>
    602646        <td class="input"><input type="text" name="familyName"
    603           value="" size="35" maxlength="255"
     647          value="" size="35" maxlength="255" onblur="nameOnChange(event)"
    604648          onkeypress="focusOnEnter(event, 'allFirstNames')"></td>
    605649        <td class="status" id="familyName.status"></td>
     
    608652      <tr valign="top">
    609653        <td class="prompt">All first names</td>
    610         <td class="input"><input type="text" name="allFirstNames"
     654        <td class="input"><input type="text" name="allFirstNames" onblur="nameOnChange(event)"
    611655          size="35" maxlength="255" onkeypress="doOnTabOrEnter(event, goNextAuto)"></td>
    612656        <td class="status" id="allFirstNames.status"></td>
     
    709753        <td class="subprompt">Plasma/serum</td>
    710754        <td class="input">
    711           <input type="checkbox" name="serum" id="serum" value="1"><label for="serum">Yes</label>
     755          <input type="checkbox" name="serum" id="serum" value="1" checked="checked"><label for="serum">Yes</label>
    712756        <td class="status" id="serum.status"></td>
    713757        <td class="help">Mark the check box if serum/plasma is available.</td>
     
    716760        <td class="prompt" id="bloodSample.prompt">Blood sample</td>
    717761        <td class="input" id="bloodSample.input">
    718           <select name="bloodSample">
     762          <select onkeypress="focusOnEnter(event, 'otherPathNote')"
     763            name="bloodSample"
     764          >
    719765            <option selected value="">unknown
    720766            <option value="PreNeo">PreNeo
     
    724770        <td class="status" id="bloodSample.status"></td>
    725771        <td class="help"><span id="bloodSample.message" class="message" style="display: none;"></span></td>
     772      </tr>
     773      <tr>
     774        <td class="prompt" id="otherPathNote.prompt">Other path note</td>
     775        <td class="input" id="otherPathNote.input"><textarea rows="3" cols="30"
     776          name="otherPathNote" value="" onkeypress="doOnTab(event, goNextAuto)"></textarea></td>
     777        <td class="status" id="otherPathNote.status"></td>
     778        <td class="help"><span id="otherPathNote.message" class="message" style="display: none;"></span></td>
    726779      </tr>
    727780      <tr id="copyConsentSection" style="display: none;">
  • extensions/net.sf.basedb.reggie/branches/ticket-422/resources/css/reggie.css

    r1742 r1782  
    155155{
    156156  content: url('../images/ok.png');
     157}
     158.status.new:before
     159{
     160  content: url('../images/new.png');
    157161}
    158162.success ul
  • extensions/net.sf.basedb.reggie/branches/ticket-422/resources/histology_block.jsp

    r1726 r1782  
    213213  html += '<th>Paraffin block</th>';
    214214  html += '<th>Storage box</th>';
     215  html += '<th>Comment</th>';
    215216  html += '</tr>';
    216217  html += '</thead>';
     
    223224
    224225    html += '<tr>';
    225     html += '<td style="width: 150px;">' + block.name + '</td>';
     226    html += '<td style="width: 120px;">' + block.name + '</td>';
    226227    html += '<td><input type="text" name="blockBox'+blockNo+'" value="<%=lastBlockBox%>" onblur="blockBoxOnChange('+blockNo+')"';
    227228    html += ' onkeypress="' + nextStep + '" size="10" ></td>';
     229    html += '<td><input type="text" name="blockComment'+blockNo+'" value="" size="35"></td>';
    228230    html += '</tr>';
    229231  }
     
    278280    var block = workList.blocks[blockNo];
    279281    block.storageBox = frm['blockBox'+blockNo].value;
     282    block.comment = frm['blockComment'+blockNo].value;
    280283    frm['blockBox'+blockNo].disabled = true;
     284    frm['blockComment'+blockNo].disabled = true;
    281285  }
    282286
  • extensions/net.sf.basedb.reggie/branches/ticket-422/resources/histology_glass.jsp

    r1726 r1782  
    3535
    3636var paraffinBlock;
     37var existingNumberOfHEGlass = 0;
    3738var stainDateIsValid = false;
     39var numHEGlassIsValid = false;
    3840
    3941function init()
     
    221223 
    222224  setInnerHTML('blockName', paraffinBlock.name);
    223 
     225  frm.comment.value = paraffinBlock.comment;
     226  if (heGlass)
     227  {
     228    frm.numberOfHEGlass.value = heGlass.length;
     229    existingNumberOfHEGlass = heGlass.length;
     230  }
     231 
    224232  var numWells = 0;
    225233  for (var i = 0; i < paraffinBlock.bioWells.length; i++)
     
    263271 
    264272  stainDateOnChange();
    265   frm['idx.0.0'].focus();
     273  frm['numberOfHEGlass'].focus();
    266274}
    267275
     
    325333function step2IsValid()
    326334{
    327  
    328   var frm = document.forms['reggie'];
    329  
     335  var frm = document.forms['reggie'];
     336  if (!numHEGlassIsValid)
     337  {
     338    frm.numberOfHEGlass.focus();
     339    return false;
     340  }
     341 
     342  var numHEGlass = parseInt(frm.numberOfHEGlass.value, 10);
    330343  var allValid = true;
    331344  for (var i = 0; i < wells.length; i++)
    332345  {
    333346    var field = frm[wells[i]];
    334     if (!(parseInt(field.value, 10) > 0))
     347    var indexValue = parseInt(field.value, 10);
     348    if (!indexValue || indexValue <= 0 || indexValue > numHEGlass)
    335349    {
    336350      setInputStatus(field.name, null, 'invalid');
     
    338352      allValid = false;
    339353    }
     354    else
     355    {
     356      setInputStatus(field.name, null, 'valid');
     357    }
    340358  }
    341359 
    342360  if (!allValid)
    343361  {
    344     setInputStatus('index', 'Value must be >= 1', 'invalid');
     362    setInputStatus('index', 'Value must be between 1–' + numHEGlass, 'invalid');
    345363    return false;
    346364  }
     
    358376{
    359377  var frm = document.forms['reggie'];
    360   if (!(parseInt(frm[field].value, 10) > 0))
    361   {
    362     frm[field].focus();
     378 
     379  var numHEGlass = parseInt(frm.numberOfHEGlass.value, 10) || 1;
     380  var indexValue = parseInt(frm[field].value, 10);
     381
     382  if (!indexValue || indexValue <= 0 || indexValue > numHEGlass)
     383  {
    363384    setInputStatus(field, null, 'invalid');
     385    setInputStatus('index', 'Must be between 1–'+numHEGlass, '');
    364386    return;
    365387  }
    366388
    367389  setInputStatus(field, null, 'valid');
    368  
     390  setInputStatus('index', '', '');
     391}
     392
     393function checkNumHEGlass()
     394{
     395  var frm = document.forms['reggie'];
     396  numHEGlassIsValid = false;
     397 
     398  var numHEGlass = parseInt(frm.numberOfHEGlass.value, 10) || 0;
     399  var limit = Math.max(1, existingNumberOfHEGlass);
     400  if (numHEGlass < limit)
     401  {
     402    setInputStatus('numberOfHEGlass', 'Must be a value &gt;= ' + limit, 'invalid');
     403    return;
     404  }
     405 
     406  setInputStatus('numberOfHEGlass', '', 'valid');
     407  numHEGlassIsValid = true;
     408 
     409  for (var i = 0; i < wells.length; i++)
     410  {
     411    checkIndexValue(wells[i]);
     412  }
     413
    369414}
    370415
     
    374419
    375420  var frm = document.forms['reggie'];
    376  
    377   var maxIndex = 1;
     421  frm.stainDate.disabled = true;
     422  frm.stainingProtocol.disabled = true;
     423  frm.comment.disabled = true;
     424  frm.numberOfHEGlass.disabled = true;
     425 
     426  var numHEGlass = parseInt(frm.numberOfHEGlass.value, 10);
    378427  for (var i = 0; i < wells.length; i++)
    379428  {
    380429    var field = frm[wells[i]];
    381430    field.disabled = true;
    382     if (parseInt(field.value, 10) > maxIndex)
    383     {
    384       maxIndex = parseInt(field.value, 10);
    385     }
    386431  }
    387432
     
    407452  var heGlass = paraffinBlock.heGlass;
    408453 
    409   for (var glassNo = 0; glassNo < maxIndex; glassNo++)
    410   {
    411     var nextStep = glassNo < (maxIndex-1) ? 'focusOnEnter(event, \'glassNo'+(glassNo+1)+'\')' : '';
     454  for (var glassNo = 0; glassNo < numHEGlass; glassNo++)
     455  {
     456    var nextStep = glassNo < (numHEGlass-1) ? 'focusOnEnter(event, \'glassBox'+(glassNo+1)+'\');' : '';
    412457    var heSlide = new Object();
    413458   
     
    440485    }
    441486
    442     html += '<tr>';
    443     html += '<td style="width: 150px;">' + heSlide.name + '</td>';
     487    html += '<tr style="border-top: 1px dotted #A0A0A0;">';
     488    html += '<td style="width: 120px;">' + heSlide.name + '</td>';
    444489    html += '<td><input type="text" name="glassBox'+glassNo+'" value="'+heSlide.storageBox+'" onblur="glassBoxOnChange('+glassNo+')"';
    445490    html += ' onkeypress="focusOnEnter(event, \'position'+glassNo+'\'); return Numbers.integerOnly(event)" size="10" ></td>';
    446491    html += '<td><input type="text" name="position'+glassNo+'" value="'+heSlide.position+'" onblur="glassBoxOnChange('+glassNo+')"';
    447     html += ' onkeypress="' + nextStep + '; return Numbers.integerOnly(event)" size="10" ></td>';
     492    html += ' onkeypress="'+nextStep+' return Numbers.integerOnly(event)" size="10" ></td>';
    448493    html += '<td class="status" id="glassBox'+glassNo+'.status"></td>';
     494    html += '</tr>';
     495   
     496    html += '<tr>';
     497    html += '<td style="width: 120px;" class="subprompt">- comment</td>';
     498    html += '<td colspan="2"><input type="text" name="comment'+glassNo+'" value="" style="width: 100%;"></td>';
     499    html += '<td class="status"></td>';
    449500    html += '</tr>';
    450501  }
     
    453504  setInnerHTML('glassBoxInput', html);
    454505 
     506  for (var glassNo = 0; glassNo < numHEGlass; glassNo++)
     507  {
     508    if (heGlass && heGlass[glassNo])
     509    {
     510      frm['comment'+glassNo].value = heGlass[glassNo].comment;
     511      glassBoxOnChange(glassNo);
     512    }
     513    else
     514    {
     515      setInputStatus('glassBox'+glassNo, null, 'new');
     516    }
     517  }
     518 
    455519  frm.glassBox0.focus();
    456520}
     
    462526  if (frm['glassBox'+glassNo].value == '')
    463527  {
    464     setInputStatus('glassBox'+glassNo, null, 'invalid');
     528    setInputStatus('glassBox'+glassNo, 'Missing storage box', 'invalid');
    465529    return;
    466530  }
    467531  if (frm['position'+glassNo].value == '')
    468532  {
    469     setInputStatus('glassBox'+glassNo, null, 'invalid');
     533    setInputStatus('glassBox'+glassNo, 'Missing position', 'invalid');
    470534    return;
    471535  }
     
    554618    heGlass.storageBox = frm['glassBox'+glassNo].value;
    555619    heGlass.position = frm['position'+glassNo].value;
     620    heGlass.comment = frm['comment'+glassNo].value;
    556621    glassNo++;
    557622  }
     
    560625  paraffinBlock.stainDate = frm.stainDate.value;
    561626  paraffinBlock.protocolId = parseInt(frm.stainingProtocol[frm.stainingProtocol.selectedIndex].value, 10);
     627  paraffinBlock.comment = frm.comment.value;
    562628  submitInfo.paraffinBlock = paraffinBlock;
    563629 
     
    652718  {
    653719    padding: 2px;
    654     text-align: left;
    655720  }
    656721
     
    730795        <tr valign="top">
    731796          <td class="prompt">Protocol</td>
    732           <td class="input"><select style="width:90%" name="stainingProtocol" id="stainingProtocol"
     797          <td class="input"><select style="width:95%" name="stainingProtocol" id="stainingProtocol"
    733798            ></select></td>
    734799          <td class="status" id="stainingProtocol.status"></td>
     
    742807          <td class="status" id="paraffinblock.status"></td>
    743808          <td class="help"></td>
     809        </tr>
     810        <tr valign="top">
     811          <td class="subprompt">- comment</td>
     812          <td class="input"><textarea name="comment" rows="2" style="width: 95%;"></textarea></td>
     813          <td class="status" id="comment.status"></td>
     814          <td class="help"></td>
     815        </tr>
     816        <tr valign="top">
     817          <td class="prompt">HE slides created</td>
     818          <td class="input"><input type="text" size="4"
     819            name="numberOfHEGlass" value="2"
     820            onblur="checkNumHEGlass()"
     821            onkeypress="focusOnEnter(event, 'idx.0.0'); return Numbers.integerOnly(event)">
     822          </td>
     823          <td class="status" id="numberOfHEGlass.status"></td>
     824          <td class="help"><span id="numberOfHEGlass.message" class="message" style="display: none;"></span>
     825            Enter the total number of HE glass slides that has been created from the selected paraffin block.
     826          </td>
    744827        </tr>
    745828       
  • extensions/net.sf.basedb.reggie/branches/ticket-422/resources/histology_protocol2.jsp

    r1726 r1782  
    147147  function downloadHEGlassLabels()
    148148  {
    149     var numLabelsPerBlock = prompt('Number of labels per block?', 5);
     149    var numLabelsPerBlock = prompt('Number of labels per block?', 3);
    150150    if (numLabelsPerBlock == null) return;
    151151   
  • extensions/net.sf.basedb.reggie/branches/ticket-422/resources/index.jsp

    r1762 r1782  
    272272            <li>Consent count report</li>
    273273            <li>Patient count report</li>
     274            <li>Overview report</li>
     275            <li>Missing sample data report</li>
    274276            </ul>
    275277          </dd>
  • extensions/net.sf.basedb.reggie/branches/ticket-422/resources/persinfo.jsp

    r1726 r1782  
    7474    if (frm.allFirstNames.value == '')
    7575    {
    76       setInputStatus('allFirstNames', 'Missing', 'invalid');
    77       frm.allFirstNames.focus();
     76      setInputStatus('allFirstNames', 'Missing', 'warning');
    7877      formOk = false;
    7978    }
     
    8584    if (frm.familyName.value == '')
    8685    {
    87       setInputStatus('familyName', 'Missing', 'invalid');
    88       frm.familyName.focus();
     86      setInputStatus('familyName', 'Missing', 'warning');
    8987      formOk = false;
    9088    }
     
    109107    if (frm.existingAllFirstNames.value == '')
    110108    {
    111       setInputStatus('existingAllFirstNames', 'Missing', 'invalid');
    112       frm.existingAllFirstNames.focus();
     109      setInputStatus('existingAllFirstNames', 'Missing', 'warning');
    113110      formOk = false;
    114111    }
     
    120117    if (frm.existingFamilyName.value == '')
    121118    {
    122       setInputStatus('existingFamilyName', 'Missing', 'invalid');
    123       frm.existingFamilyName.focus();
     119      setInputStatus('existingFamilyName', 'Missing', 'warning');
    124120      formOk = false;
    125121    }
     
    132128  return formOk;
    133129}
     130
     131function step2IsAcceptable()
     132{
     133  var formOk = true;
     134  var frm = document.forms['reggie'];
     135  // New patient only
     136  if (!patientInfo.id)
     137  {
     138    formOk = frm.patientCode.value != '';
     139  }
     140  return formOk;
     141}
     142
     143
    134144
    135145function step3IsValid()
     
    173183  else if (currentStep == 2)
    174184  {
    175     if (step2IsValid()) gotoStep3();
     185    if (step2IsValid())
     186    {
     187      gotoStep3();
     188    }
     189    else if (step2IsAcceptable())
     190    {
     191      if (manual)
     192      {
     193        gotoStep3();
     194      }
     195      else
     196      {
     197        setInnerHTML('gonext.message', 'Missing name(s). Click \'Next\' to continue registration.');
     198      }
     199    }
    176200  }
    177201}
     
    253277}
    254278
     279function nameOnChange(event)
     280{
     281  var field = event.target;
     282  if (field.value == '')
     283  {
     284    setInputStatus(field.name, 'Missing', 'warning');
     285  }
     286  else
     287  {
     288    setInputStatus(field.name, '', 'valid');
     289  }
     290}
     291
    255292function lateralityOnChange()
    256293{
     
    351388    }
    352389   
    353     if (!Dates.isDate(samplingDate, 'yyyyMMdd'))
     390    if (samplingDate != '' && !Dates.isDate(samplingDate, 'yyyyMMdd'))
    354391    {
    355392      setInputStatus('samplingDate', 'Not a valid date', 'invalid');
     
    366403      }
    367404    }
    368     setInputStatus('samplingDate', '', 'valid');
     405    if (samplingDate == '')
     406    {
     407      setInputStatus('samplingDate', 'Missing', 'warning');
     408    }
     409    else
     410    {
     411      setInputStatus('samplingDate', '', 'valid');
     412    }
    369413  }
    370414  samplingDateIsValid = true;
     
    409453  {
    410454    var samplingTimestamp = Dates.parseString(frm.samplingDate.value + ' ' + frm.samplingTime.value, 'yyyyMMdd Hmm');
    411     if (samplingTimestamp && rnaLaterTimestamp.getDate() != samplingTimestamp.getDate())
    412     {
    413       setInputStatus('rnaLaterDate', 'Sampling and RNA later dates are different', 'warning');
     455    if (samplingTimestamp)
     456    {
     457      if (rnaLaterTimestamp.getDate() != samplingTimestamp.getDate())
     458      {
     459        setInputStatus('rnaLaterDate', 'Sampling and RNA later dates are different', 'warning');
     460      }
     461      else if (rnaLaterTimestamp.getTime() < samplingTimestamp.getTime())
     462      {
     463        setInputStatus('rnaLaterDate', 'RNA later time is before Sampling time', 'warning');
     464      }
    414465    }
    415466  }
     
    929980        <td class="prompt">Family name</td>
    930981        <td class="input"><input type="text" name="familyName"
    931           value="" size="35" maxlength="255"
     982          value="" size="35" maxlength="255" onblur="nameOnChange(event)"
    932983          onkeypress="focusOnEnter(event, 'allFirstNames')"></td>
    933984        <td class="status" id="familyName.status"></td>
     
    936987      <tr valign="top">
    937988        <td class="prompt">All first names</td>
    938         <td class="input"><input type="text" name="allFirstNames"
     989        <td class="input"><input type="text" name="allFirstNames" onblur="nameOnChange(event)"
    939990          size="35" maxlength="255" onkeypress="doOnTabOrEnter(event, goNextAuto)"></td>
    940991        <td class="status" id="allFirstNames.status"></td>
     
    9771028        <td class="prompt">Family name</td>
    9781029        <td class="input"><input type="text" name="existingFamilyName"
    979           value="" size="35" maxlength="255"
     1030          value="" size="35" maxlength="255" onblur="nameOnChange(event)"
    9801031          onkeypress="focusOnEnter(event, 'existingAllFirstNames')"></td>
    9811032        <td class="status" id="existingFamilyName.status"></td>
     
    9841035      <tr valign="top">
    9851036        <td class="prompt">All first names</td>
    986         <td class="input"><input type="text" name="existingAllFirstNames"
     1037        <td class="input"><input type="text" name="existingAllFirstNames" onblur="nameOnChange(event)"
    9871038          size="35" maxlength="255" onkeypress="doOnTabOrEnter(event, goNextAuto)"></td>
    9881039        <td class="status" id="existingAllFirstNames.status"></td>
  • extensions/net.sf.basedb.reggie/branches/ticket-422/resources/samplereportgenerator.jsp

    r1757 r1782  
    3434  var unknownSite = 0;
    3535  var unknownCreation;
     36  var numPatientsNoSamples = 0;
    3637 
    3738  var month=new Array(12);
     
    6364    var frm = document.forms['reggie'];
    6465    frm.reporttype.disabled = true;
     66    // Hide report period input fields
     67    document.getElementById("reportPeriodSubSection01").style.display = 'none';
     68    document.getElementById("reportPeriodSubSection02").style.display = 'none';
     69    document.getElementById("reportPeriodSubSection04").style.display = 'none';
     70    // Hide view type pop-up menu
     71    document.getElementById("viewTypeSubSection01").style.display = 'none';
     72    document.getElementById("viewTypeSubSection02").style.display = 'none';
     73    document.getElementById("viewTypeSubSection04").style.display = 'none';
    6574    // Hide sample type pop-up menu
    6675    document.getElementById("sampleTypeSubSection01").style.display = 'none';
     
    6978    if (frm.reporttype[frm.reporttype.selectedIndex].value == 'samplecount')
    7079    {
    71       // Set item name for report period text
    72       document.getElementById("items01").innerHTML="tubes";
     80      // Show report period input fields
     81      document.getElementById("reportPeriodSubSection01").style.display = 'block';
     82      document.getElementById("reportPeriodSubSection02").style.display = 'block';
     83      document.getElementById("reportPeriodSubSection04").style.display = 'block';
     84      document.getElementById("reportPeriodSubSection01Header").innerHTML="Report period";
     85      document.getElementById("reportPeriodSubSection04HelpText").innerHTML="Define which period the report should cover. Empty fields will include all tubes.";
    7386      // Set item name for report time step text
    7487      document.getElementById("items02").innerHTML="samples";
     
    87100    else if (frm.reporttype[frm.reporttype.selectedIndex].value == 'consentcount')
    88101    {
    89       // Set item name for report period text
    90       document.getElementById("items01").innerHTML="consents";
    91       // Hide view type pop-up menu
    92       document.getElementById("viewTypeSubSection01").style.display = 'none';
    93       document.getElementById("viewTypeSubSection02").style.display = 'none';
    94       document.getElementById("viewTypeSubSection04").style.display = 'none';
     102      // Show report period input fields
     103      document.getElementById("reportPeriodSubSection01").style.display = 'block';
     104      document.getElementById("reportPeriodSubSection02").style.display = 'block';
     105      document.getElementById("reportPeriodSubSection04").style.display = 'block';
     106      document.getElementById("reportPeriodSubSection01Header").innerHTML="Report period";
     107      document.getElementById("reportPeriodSubSection04HelpText").innerHTML="Define which period the report should cover. Empty fields will include all consents.";
    95108    }
    96109    else if (frm.reporttype[frm.reporttype.selectedIndex].value == 'patientcount')
    97110    {
    98       // Set item name for report period text
    99       document.getElementById("items01").innerHTML="patients";
     111      // Show report period input fields
     112      document.getElementById("reportPeriodSubSection01").style.display = 'block';
     113      document.getElementById("reportPeriodSubSection02").style.display = 'block';
     114      document.getElementById("reportPeriodSubSection04").style.display = 'block';
     115      document.getElementById("reportPeriodSubSection01Header").innerHTML="Report period";
     116      document.getElementById("reportPeriodSubSection04HelpText").innerHTML="Define which period the report should cover. Empty fields will include all patients.";
    100117      // Set item name for report time step text
    101118      document.getElementById("items02").innerHTML="patients";
     
    108125      document.getElementById("viewTypeSubSection04").style.display = 'block';
    109126    }
     127    else if (frm.reporttype[frm.reporttype.selectedIndex].value == 'overviewreport')
     128    {
     129      // Set parameters (report period) help text
     130      document.getElementById("reportPeriodSubSection01").style.display = 'block';
     131      document.getElementById("reportPeriodSubSection04").style.display = 'block';
     132      document.getElementById("reportPeriodSubSection01Header").innerHTML="No report parameters";
     133      document.getElementById("reportPeriodSubSection04HelpText").innerHTML="Overview report will be generated irrespective of date for items.";
     134    }
     135    else if (frm.reporttype[frm.reporttype.selectedIndex].value == 'missingsampledatareport')
     136    {
     137      // Show sample type pop-up menu
     138      document.getElementById("sampleTypeSubSection01").style.display = 'block';
     139      document.getElementById("sampleTypeSubSection02").style.display = 'block';
     140      document.getElementById("sampleTypeSubSection04").style.display = 'block';
     141    }
    110142    Main.show('itemCountSection');
    111143       
     
    179211      frm.sampletype.disabled = true;
    180212    }
    181     if (reportType == 'patientcount')
     213    else if (reportType == 'patientcount')
    182214    {
    183215      frm.viewtype.disabled = true;
     216    }
     217    else if (reportType == 'missingsampledatareport')
     218    {
     219      frm.sampletype.disabled = true;
    184220    }
    185221    Main.hide('gocreate');
     
    194230      if (frm.sampletype.value != null) url += '&stype='+frm.sampletype.value;
    195231    }
    196     if (reportType == 'patientcount')
     232    else if (reportType == 'patientcount')
    197233    {     
    198234      if (frm.viewtype.value != null) url += '&vtype='+frm.viewtype.value;
     235    }
     236    else if (reportType == 'missingsampledatareport')
     237    {     
     238      if (frm.sampletype.value != null) url += '&stype='+frm.sampletype.value;
    199239    }
    200240   
     
    211251    }
    212252    var report = response.report;
     253    var permissionDeniedForPatientName = report.permissionDeniedForPatientName;
    213254    var reportTable;
    214255   
     
    223264        reportTable = createConsentCountReport(report);
    224265      }
    225       if ('patientcount' == reportType)
     266      else if ('patientcount' == reportType)
    226267      {     
    227268        reportTable = createItemCountReport(report, reportType);
     269      }
     270      else if ('overviewreport' == reportType)
     271      {     
     272        reportTable = createOverviewReport(report);
     273      }
     274      else if ('missingsampledatareport' == reportType)
     275      {     
     276        reportTable = createMissingSampleDataReport(report);
    228277      }
    229278    }
     
    248297      cellElement.appendChild(unknownDateTable);
    249298    }
     299    else if ('overviewreport' == reportType)
     300    {
     301      var spacer = document.createElement('text');
     302      spacer.innerHTML = "<BR>";
     303      cellElement.appendChild(spacer);
     304      var patientDetailedTable = createOverviewPatientDetailedTable(report);
     305      cellElement.appendChild(patientDetailedTable);
     306    }
    250307    // Summary list
    251308    var summaryList = document.createElement('ul');
     
    255312    {
    256313      var samples = 'specimens';
    257       if ('blood' == sampleType)
     314      if ('nospecimen' == sampleType)
     315      {
     316        samples = '"no specimens"';
     317      }
     318      else if ('blood' == sampleType)
    258319      {
    259320        samples = 'blood samples';
     
    288349    }
    289350    else if ('patientcount' == reportType)
    290     {     
     351    {
    291352      summaryList.appendChild(getListElement(unknownSite + ' patients registered to unknown sites.'));
    292353      summaryList.appendChild(getListElement(unknownCreation + ' patients without creation date. These are included in the \'Total\' column.'));
     354    }
     355    else if ('overviewreport' == reportType)
     356    {
     357      summaryList.appendChild(getListElement(unknownSite + ' patients registered to unknown sites.'));
     358      summaryList.appendChild(getListElement(numPatientsNoSamples + ' patients with no samples.'));
     359      summaryList.appendChild(getListElement('Note: Consents of type "Yes" include consents without patient id (PAT#) or date.'));
     360    }
     361    else if ('missingsampledatareport' == reportType)
     362    {
     363      summaryList.appendChild(getListElement('Note: Patient name is considered missing if either "all first names" or "family name" is missing.'));
     364      if ('true' == permissionDeniedForPatientName)
     365      {
     366        var patientNamePermissionWarningIconWithMessage = document.createElement('img');
     367        patientNamePermissionWarningIconWithMessage.innerHTML = '<img src="images/warning.png"> Sorry, logged-in user does not have permission to check patient names.</img>';
     368        var patientNamePermissionWarningListElement = document.createElement('li');
     369        patientNamePermissionWarningListElement.appendChild(patientNamePermissionWarningIconWithMessage);
     370        summaryList.appendChild(patientNamePermissionWarningListElement);
     371      }
    293372    }
    294373    cellElement.appendChild(summaryList);
     
    309388    var psdString = report.periodBeginDate;
    310389    var ldString = report.latestDate;
    311     var startDate = new Date();
    312     startDate.setYear(sdString.substr(0,4));
    313     startDate.setMonth(sdString.substr(4,2)-1);
    314     startDate.setDate(sdString.substr(6));
    315     var endDate = new Date();
    316     endDate.setYear(edString.substr(0,4));
    317     endDate.setMonth(edString.substr(4,2)-1);
    318     endDate.setDate(edString.substr(6));
    319     var periodStartDate = new Date();
    320     periodStartDate.setYear(psdString.substr(0,4));
    321     periodStartDate.setMonth(psdString.substr(4,2)-1);
    322     periodStartDate.setDate(psdString.substr(6));
    323     var latestDate;
    324     if (ldString != null)
    325     {
    326       latestDate = new Date();
    327       latestDate.setYear(ldString.substr(0,4));
    328       latestDate.setMonth(ldString.substr(4,2)-1);
    329       latestDate.setDate(ldString.substr(6));
    330     }   
     390    var startDate = dateStrToDate(sdString);
     391    var endDate = dateStrToDate(edString);
     392    var periodStartDate = dateStrToDate(psdString);
     393    var latestDate = dateStrToDate(ldString);
    331394   
    332395    var viewType = report.viewType;   
     
    338401   
    339402    var headerText = '# Items by ';
     403    var startDateStr = addHyphensToDateString(sdString);
     404    var endDateStr = addHyphensToDateString(edString);
     405    var latestDateStr = addHyphensToDateString(ldString);
    340406    if ('samplecount' == reportType)
    341407    {
    342408      headerText = '# Specimens by ';
    343       if ('blood' == sampleType)
     409      if ('nospecimen' == sampleType)
     410      {
     411        headerText = '# "No specimens" by ';
     412      }
     413      else if ('blood' == sampleType)
    344414      {
    345415        headerText = '# Blood samples by ';
     
    393463     
    394464    // Set table header
    395     headerText += ' (between ' + startDate.getFullYear()+'-';
    396     if ((startDate.getMonth()+1) < 10)
    397     {
    398       headerText += '0' + (startDate.getMonth()+1);
    399     }
    400     else
    401     {
    402       headerText += (startDate.getMonth()+1);
    403     }
    404     headerText += '-';
    405     if (startDate.getDate() < 10)
    406     {
    407       headerText += '0' + startDate.getDate();
    408     }
    409     else
    410     {
    411       headerText += startDate.getDate();
    412     }
    413     headerText += ' and ';
    414     headerText += endDate.getFullYear()+'-';
    415     if ((endDate.getMonth()+1) < 10)
    416     {
    417       headerText += '0' + (endDate.getMonth()+1);
    418     }
    419     else
    420     {
    421       headerText += (endDate.getMonth()+1);
    422     }
    423     headerText += '-';
    424     if (endDate.getDate() < 10)
    425     {
    426       headerText += '0' + endDate.getDate();
    427     }
    428     else
    429     {
    430       headerText += endDate.getDate();
    431     }
    432     headerText += ')';
     465    headerText += ' (between ' + startDateStr + ' and ' + endDateStr + ')';
    433466    if (latestDate != null)
    434467    {
    435       headerText += '\nLast registration ' + latestDate.getFullYear();
    436       headerText += '-';
    437       if ((latestDate.getMonth()+1) < 10)
    438       {
    439         headerText += '0';
    440       }
    441       headerText += (latestDate.getMonth()+1);
    442       headerText += '-';
    443       if (latestDate.getDate()<10)
    444       {
    445         headerText += '0';
    446       }
    447       headerText += latestDate.getDate();
     468      headerText += '\nLast registration ' + latestDateStr;
    448469    }   
    449470    headerRow.appendChild(getTableCellElement(headerText, 'reportheader', (numCols+5)));
     
    517538    var sdString = report.beginDate;
    518539    var edString = report.endDate;
    519 /*
    520     var psdString = report.periodBeginDate;
    521 */
    522540    var ldString = report.latestDate;
    523     var startDate = new Date();
    524     startDate.setYear(sdString.substr(0,4));
    525     startDate.setMonth(sdString.substr(4,2)-1);
    526     startDate.setDate(sdString.substr(6));
    527     var endDate = new Date();
    528     endDate.setYear(edString.substr(0,4));
    529     endDate.setMonth(edString.substr(4,2)-1);
    530     endDate.setDate(edString.substr(6));
    531 /*
    532     var periodStartDate = new Date();
    533     periodStartDate.setYear(psdString.substr(0,4));
    534     periodStartDate.setMonth(psdString.substr(4,2)-1);
    535     periodStartDate.setDate(psdString.substr(6));
    536 */
    537     var latestDate;
    538     if (ldString != null)
    539     {
    540       latestDate = new Date();
    541       latestDate.setYear(ldString.substr(0,4));
    542       latestDate.setMonth(ldString.substr(4,2)-1);
    543       latestDate.setDate(ldString.substr(6));
    544     }   
    545 
    546 /*   
    547     var viewType = report.viewType;
    548 */ 
    549  
     541    var startDate = dateStrToDate(sdString);
     542    var endDate = dateStrToDate(edString);
     543    var latestDate = dateStrToDate(ldString);
     544
    550545    var headerRow = document.createElement('tr');   
    551546    var subHeaderRow = document.createElement('tr');
     
    677672    addDataRowsToConsentTableUnknownDate(report, reportTable);
    678673     
    679     // Add a row with the combined numbers for all sites for each period
     674    // Add a row with the combined numbers for all sites
    680675    var sitesCombinedRow = document.createElement('tr');
    681676    sitesCombinedRow.appendChild(getTableCellElement('Sites combined', 'colsummary'));
    682677    sitesCombinedRow.appendChild(getTableCellElement('', 'colsummary', 2));
    683     // Get combined numbers for all sites for each period
     678    // Get combined numbers for all sites
    684679    var sumKey = 'sumKey';
    685680    var statistics = report.statistics;
     
    709704  }
    710705 
    711   function addHyphensToDateString(yyyymmddStr)
    712   {
    713     var dateWithHyphensStr = '????-??-??';
    714     if (yyyymmddStr != null)
    715     {
    716       var yyyyStr = yyyymmddStr.substr(0,4);
    717       var mmStr   = yyyymmddStr.substr(4,2);
    718       var ddStr = yyyymmddStr.substr(6);
    719       dateWithHyphensStr = yyyyStr + '-' + mmStr + '-' + ddStr;
    720     }
    721     return dateWithHyphensStr;
    722   }
    723 
     706  function createOverviewReport(report)
     707  {
     708    var reportTable = getReportTable();
     709    var sdString = report.beginDate;
     710    var edString = report.endDate;
     711    var ldString = report.latestDate;
     712    var startDate = dateStrToDate(sdString);
     713    var endDate = dateStrToDate(edString);
     714    var latestDate = dateStrToDate(ldString);
     715 
     716    var headerRow = document.createElement('tr');   
     717    var subHeaderRow = document.createElement('tr');
     718    var subHeader2Row = document.createElement('tr');
     719    var columnHeaderRow = document.createElement('tr');
     720   
     721    var numCols = 6;
     722    var numDecimals = 0;
     723    var headerText = 'Number of items of different kinds';
     724    var startDateStr = addHyphensToDateString(sdString);
     725    var endDateStr = addHyphensToDateString(edString);
     726    var latestDateStr = addHyphensToDateString(ldString);
     727    headerText += ' (betweeen ' + startDateStr + ' and ' + endDateStr + ')';
     728    if (latestDate != null)
     729    {
     730        headerText += '\nLast registration ' + latestDateStr;
     731    }
     732    headerRow.appendChild(getTableCellElement(headerText, 'reportheader', (numCols+3)));
     733   
     734    // Subheader
     735    subHeaderRow.appendChild(getTableCellElement('', 'reportsubheader', 3));
     736   
     737    subHeaderRow.appendChild(getTableCellElement('Patients', 'reportsubheader'));
     738    subHeaderRow.appendChild(getTableCellElement('Blood', 'reportsubheader'));
     739    subHeaderRow.appendChild(getTableCellElement('Specimens', 'reportsubheader'));
     740    subHeaderRow.appendChild(getTableCellElement('No specimens', 'reportsubheader'));
     741    subHeaderRow.appendChild(getTableCellElement('Consents', 'reportsubheader'));
     742    subHeaderRow.appendChild(getTableCellElement('Consents', 'reportsubheader'));
     743
     744    // Columnsheader   
     745    var siteHeader = getTableCellElement('Site', 'reportsubheader');     
     746    var startDateHeader = getTableCellElement('Start date','reportsubheader');
     747    var latestDateHeader = getTableCellElement('Latest date','reportsubheader');
     748    columnHeaderRow.appendChild(siteHeader);
     749    columnHeaderRow.appendChild(startDateHeader);
     750    columnHeaderRow.appendChild(latestDateHeader); 
     751   
     752    columnHeaderRow.appendChild(getTableCellElement('', 'reportsubheader'));
     753    columnHeaderRow.appendChild(getTableCellElement('samples', 'reportsubheader'));
     754    columnHeaderRow.appendChild(getTableCellElement('', 'reportsubheader'));
     755    columnHeaderRow.appendChild(getTableCellElement('', 'reportsubheader'));
     756    columnHeaderRow.appendChild(getTableCellElement('(Yes)', 'reportsubheader'));
     757    columnHeaderRow.appendChild(getTableCellElement('missing', 'reportsubheader'));
     758
     759    // Build table     
     760    reportTable.appendChild(headerRow);
     761    reportTable.appendChild(subHeaderRow);
     762    reportTable.appendChild(subHeader2Row);
     763    reportTable.appendChild(columnHeaderRow);
     764         
     765    // Data rows     
     766    addDataRowsToOverviewTable(report, reportTable);
     767     
     768    // Add a row with the combined numbers for all sites for each period
     769    var sitesCombinedRow = document.createElement('tr');
     770    sitesCombinedRow.appendChild(getTableCellElement('Sites combined', 'colsummary'));
     771    sitesCombinedRow.appendChild(getTableCellElement('', 'colsummary', 2));
     772    // Get combined numbers for all sites for each period
     773    var noDateKey = 'noDate';
     774    var sumKey = 'sumKey';
     775    var statistics = report.statistics;
     776    // Get values for use in summary section
     777    numPatientsNoSamples = statistics.patientNoSamples;
     778    var sitesCombined = statistics.sitesCombinedKey;
     779    if (sitesCombined != null)
     780    {
     781      data = getJSONData(sitesCombined, 'patient');
     782      sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     783      data = getJSONData(sitesCombined, 'bloodSample');
     784      sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     785      data = getJSONData(sitesCombined, 'specimen');
     786      sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     787      data = getJSONData(sitesCombined, 'noSpecimen');
     788      sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     789      data = getJSONData(sitesCombined, 'consentYes');
     790      sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     791      data = getJSONData(sitesCombined, 'consentMissing');
     792      sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     793    }
     794    reportTable.appendChild(sitesCombinedRow); 
     795
     796    return reportTable;
     797  }
     798 
     799  function createOverviewPatientDetailedTable(report)
     800  {
     801    var reportTable = getReportTable();
     802    var sdString = report.beginDate;
     803    var edString = report.endDate;
     804    var ldString = report.latestDate;
     805    var startDate = dateStrToDate(sdString);
     806    var endDate = dateStrToDate(edString);
     807 
     808    var headerRow = document.createElement('tr');   
     809    var subHeaderRow = document.createElement('tr');
     810    var subHeader2Row = document.createElement('tr');
     811    var columnHeaderRow = document.createElement('tr');
     812   
     813    var numCols = 8;
     814    var numDecimals = 0;
     815    var headerText = 'Patient records of different kinds';
     816    var startDateStr = addHyphensToDateString(sdString);
     817    var endDateStr = addHyphensToDateString(edString);
     818    var latestDateStr = addHyphensToDateString(ldString);
     819    headerText += ' (betweeen ' + startDateStr + ' and ' + endDateStr + ')';
     820/*
     821    if (latestDate != null)
     822    {
     823        headerText += '\nLast registration ' + latestDateStr;
     824    }
     825*/
     826    headerRow.appendChild(getTableCellElement(headerText, 'reportheader', (numCols+2)));
     827   
     828    // Subheader
     829    subHeaderRow.appendChild(getTableCellElement('', 'reportsubheader', 2));
     830   
     831    subHeaderRow.appendChild(getTableCellElement('Patients', 'reportsubheader'));
     832    subHeaderRow.appendChild(getTableCellElement('Patients', 'reportsubheader'));
     833    subHeaderRow.appendChild(getTableCellElement('Patients', 'reportsubheader'));
     834    subHeaderRow.appendChild(getTableCellElement('Patients', 'reportsubheader'));
     835    subHeaderRow.appendChild(getTableCellElement('Patients', 'reportsubheader'));
     836    subHeaderRow.appendChild(getTableCellElement('Patients', 'reportsubheader'));
     837    subHeaderRow.appendChild(getTableCellElement('Patients', 'reportsubheader'));
     838    //subHeaderRow.appendChild(getTableCellElement('Patients', 'reportsubheader'));
     839    subHeaderRow.appendChild(getTableCellElement('', 'reportsubheader'));
     840
     841    // Subheader 2
     842    subHeader2Row.appendChild(getTableCellElement('', 'reportsubheader', 2));
     843   
     844    subHeader2Row.appendChild(getTableCellElement('(blood', 'reportsubheader'));
     845    subHeader2Row.appendChild(getTableCellElement('(spec.', 'reportsubheader'));
     846    subHeader2Row.appendChild(getTableCellElement('(no spec.', 'reportsubheader'));
     847    subHeader2Row.appendChild(getTableCellElement('(blood and', 'reportsubheader'));
     848    subHeader2Row.appendChild(getTableCellElement('(blood and', 'reportsubheader'));
     849    subHeader2Row.appendChild(getTableCellElement('(spec. and', 'reportsubheader'));
     850    subHeader2Row.appendChild(getTableCellElement('(blood, spec.,', 'reportsubheader'));
     851    //subHeader2Row.appendChild(getTableCellElement('(no samples)', 'reportsubheader'));
     852    subHeader2Row.appendChild(getTableCellElement('', 'reportsubheader'));
     853
     854    // Columnsheader   
     855    var siteHeader = getTableCellElement('Site', 'reportsubheader');     
     856    var startDateHeader = getTableCellElement('Start date','reportsubheader');
     857    //var latestDateHeader = getTableCellElement('Latest date','reportsubheader');
     858    columnHeaderRow.appendChild(siteHeader);
     859    columnHeaderRow.appendChild(startDateHeader);
     860    //columnHeaderRow.appendChild(latestDateHeader); 
     861   
     862    columnHeaderRow.appendChild(getTableCellElement('only)', 'reportsubheader'));
     863    columnHeaderRow.appendChild(getTableCellElement('only)', 'reportsubheader'));
     864    columnHeaderRow.appendChild(getTableCellElement('only)', 'reportsubheader'));
     865    columnHeaderRow.appendChild(getTableCellElement('specimens)', 'reportsubheader'));
     866    columnHeaderRow.appendChild(getTableCellElement('no spec.)', 'reportsubheader'));
     867    columnHeaderRow.appendChild(getTableCellElement('no spec.)', 'reportsubheader'));
     868    columnHeaderRow.appendChild(getTableCellElement('and no spec.)', 'reportsubheader'));
     869    //columnHeaderRow.appendChild(getTableCellElement('', 'reportsubheader'));
     870
     871    columnHeaderRow.appendChild(getTableCellElement('Sum', 'reportsubheader'));
     872
     873    // Build table     
     874    reportTable.appendChild(headerRow);
     875    reportTable.appendChild(subHeaderRow);
     876    reportTable.appendChild(subHeader2Row);
     877    reportTable.appendChild(columnHeaderRow);
     878         
     879    // Data rows     
     880    addDataRowsToOverviewPatientDetailedTable(report, reportTable);
     881     
     882    // Add a row with the combined numbers for all sites
     883    var sitesCombinedRow = document.createElement('tr');
     884    sitesCombinedRow.appendChild(getTableCellElement('Sites combined', 'colsummary'));
     885    sitesCombinedRow.appendChild(getTableCellElement('', 'colsummary'));
     886    // Get combined numbers for all sites
     887    var noDateKey = 'noDate';
     888    var sumKey = 'sumKey';
     889    var statistics = report.statistics;
     890    // Get values for use in summary section
     891    numPatientsNoSamples = statistics.patientNoSamples;
     892    var sitesCombined = statistics.sitesCombinedKey;
     893    if (sitesCombined != null)
     894    {
     895      data = getJSONData(sitesCombined, 'patientBloodSampleOnly');
     896      sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     897      data = getJSONData(sitesCombined, 'patientSpecimenOnly');
     898      sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     899      data = getJSONData(sitesCombined, 'patientNoSpecimenOnly');
     900      sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     901      data = getJSONData(sitesCombined, 'patientBloodSampleAndSpecimen');
     902      sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     903      data = getJSONData(sitesCombined, 'patientBloodSampleAndNoSpecimen');
     904      sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     905      data = getJSONData(sitesCombined, 'patientSpecimenAndNoSpecimen');
     906      sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     907      data = getJSONData(sitesCombined, 'patientBloodSampleAndSpecimenAndNoSpecimen');
     908      sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     909      //data = getJSONData(sitesCombined, 'patientNoSamples');
     910      //sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     911      data = getJSONData(sitesCombined, 'sumKey');
     912      sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     913    }
     914    reportTable.appendChild(sitesCombinedRow); 
     915
     916    return reportTable;
     917  }
     918 
     919  function createMissingSampleDataReport(report)
     920  {
     921    var reportTable = getReportTable();
     922    var sdString = report.beginDate;
     923    var edString = report.endDate;
     924    var ldString = report.latestDate;
     925    var startDate = dateStrToDate(sdString);
     926    var endDate = dateStrToDate(edString);
     927    var latestDate = dateStrToDate(ldString);
     928
     929    var sampleType = report.sampleType;
     930    var permissionDeniedForPatientName = report.permissionDeniedForPatientName;
     931
     932    var headerRow = document.createElement('tr');   
     933    var subHeaderRow = document.createElement('tr');
     934    var subHeader2Row = document.createElement('tr');
     935    var columnHeaderRow = document.createElement('tr');
     936   
     937    var numCols = 5;
     938    if (sampleType == 'specimen')
     939    {
     940      numCols = 5;
     941    }
     942    else if (sampleType == 'nospecimen')
     943    {
     944      numCols = 2;
     945    }
     946    else if (sampleType == 'blood')
     947    {
     948      numCols = 3;
     949    }
     950    var numDecimals = 0;
     951    var headerText = 'Number of missing specimen items of different kinds';
     952    if ('nospecimen' == sampleType)
     953    {
     954      headerText = 'Number of missing "no specimen" items of different kinds';
     955    }
     956    else if ('blood' == sampleType)
     957    {
     958      headerText = 'Number of missing blood sample items of different kinds';
     959    }
     960    var startDateStr = addHyphensToDateString(sdString);
     961    var endDateStr = addHyphensToDateString(edString);
     962    var latestDateStr = addHyphensToDateString(ldString);
     963    headerText += ' (betweeen ' + startDateStr + ' and ' + endDateStr + ')';
     964    if (latestDate != null)
     965    {
     966        headerText += '\nLast registration ' + latestDateStr;
     967    }
     968    headerRow.appendChild(getTableCellElement(headerText, 'reportheader', (numCols+3)));
     969   
     970    // Subheader
     971    subHeaderRow.appendChild(getTableCellElement('', 'reportsubheader', 3));
     972   
     973    subHeaderRow.appendChild(getTableCellElement('Patient', 'reportsubheader'));
     974    if (sampleType == 'specimen')
     975    {
     976      subHeaderRow.appendChild(getTableCellElement('PAD', 'reportsubheader'));
     977      subHeaderRow.appendChild(getTableCellElement('Laterality', 'reportsubheader'));
     978      subHeaderRow.appendChild(getTableCellElement('Sampling', 'reportsubheader'));
     979      subHeaderRow.appendChild(getTableCellElement('RNALater', 'reportsubheader'));
     980    }
     981    else if (sampleType == 'nospecimen')
     982    {
     983      subHeaderRow.appendChild(getTableCellElement('Sampling', 'reportsubheader'));
     984    }
     985    else if (sampleType == 'blood')
     986    {
     987      subHeaderRow.appendChild(getTableCellElement('Blood sampling', 'reportsubheader'));
     988      subHeaderRow.appendChild(getTableCellElement('Blood freezer', 'reportsubheader'));
     989    }
     990
     991    // Columnsheader   
     992    var siteHeader = getTableCellElement('Site', 'reportsubheader');     
     993    var startDateHeader = getTableCellElement('Start date','reportsubheader');
     994    var latestDateHeader = getTableCellElement('Latest date','reportsubheader');
     995    columnHeaderRow.appendChild(siteHeader);
     996    columnHeaderRow.appendChild(startDateHeader);
     997    columnHeaderRow.appendChild(latestDateHeader); 
     998   
     999    columnHeaderRow.appendChild(getTableCellElement('name', 'reportsubheader'));
     1000    if (sampleType == 'specimen')
     1001    {
     1002      columnHeaderRow.appendChild(getTableCellElement('reference', 'reportsubheader'));
     1003      columnHeaderRow.appendChild(getTableCellElement('', 'reportsubheader'));
     1004      columnHeaderRow.appendChild(getTableCellElement('date', 'reportsubheader'));
     1005      columnHeaderRow.appendChild(getTableCellElement('date', 'reportsubheader'));
     1006    }
     1007    else if (sampleType == 'nospecimen')
     1008    {
     1009      columnHeaderRow.appendChild(getTableCellElement('date', 'reportsubheader'));
     1010    }
     1011    else if (sampleType == 'blood')
     1012    {
     1013      columnHeaderRow.appendChild(getTableCellElement('date', 'reportsubheader'));
     1014      columnHeaderRow.appendChild(getTableCellElement('date', 'reportsubheader'));
     1015    }
     1016
     1017    // Build table     
     1018    reportTable.appendChild(headerRow);
     1019    reportTable.appendChild(subHeaderRow);
     1020    reportTable.appendChild(columnHeaderRow);
     1021         
     1022    // Data rows     
     1023    addDataRowsToMissingSampleDataTable(report, reportTable);
     1024     
     1025    // Add a row with the combined numbers for all sites for each period
     1026    var sitesCombinedRow = document.createElement('tr');
     1027    sitesCombinedRow.appendChild(getTableCellElement('Sites combined', 'colsummary'));
     1028    sitesCombinedRow.appendChild(getTableCellElement('', 'colsummary', 2));
     1029    // Get combined numbers for all sites for each period
     1030    var noDateKey = 'noDate';
     1031    var sumKey = 'sumKey';
     1032    var statistics = report.statistics;
     1033    var sitesCombined = statistics.sitesCombinedKey;
     1034    if (sitesCombined != null)
     1035    {
     1036      if ('false' == permissionDeniedForPatientName)
     1037      {
     1038        data = getJSONData(sitesCombined, 'missingPatientName');
     1039        sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     1040      }
     1041      else
     1042      {
     1043        data = '-';
     1044        sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     1045      }
     1046      if (sampleType == 'specimen')
     1047      {
     1048        data = getJSONData(sitesCombined, 'missingPadReference');
     1049        sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     1050        data = getJSONData(sitesCombined, 'missingLaterality');
     1051        sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     1052        data = getJSONData(sitesCombined, 'missingSamplingDateTime');
     1053        sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     1054        data = getJSONData(sitesCombined, 'missingRnaLaterDateTime');
     1055        sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     1056      }
     1057      else if (sampleType == 'nospecimen')
     1058      {
     1059        data = getJSONData(sitesCombined, 'missingSamplingDateTime');
     1060        sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     1061      }
     1062      else if (sampleType == 'blood')
     1063      {
     1064        data = getJSONData(sitesCombined, 'missingBloodSamplingDateTime');
     1065        sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     1066        data = getJSONData(sitesCombined, 'missingBloodFreezerDateTime');
     1067        sitesCombinedRow.appendChild(getTableCellElement(data, 'colsummary'));
     1068      }
     1069    }
     1070    reportTable.appendChild(sitesCombinedRow); 
     1071
     1072    return reportTable;
     1073  }
     1074 
    7241075  function createConsentTablePatientsWithMultipleDates(report)
    7251076  {
     
    8031154      if (!sites.hasOwnProperty(namePrefix)) continue;       
    8041155      var site = sites[namePrefix];
    805       var siteName = site.name;       
    806       var year = site.startDate.substr(0,4);
    807       var month = site.startDate.substr(5,2);
    808       var date = site.startDate.substr(8,2);     
    809       var siteStartDate = new Date(year, month-1, date);
     1156      var siteName = site.name;
     1157      var siteStartDate = dateStrToDate(site.startDate);
     1158      var siteStartDateStr = addHyphensToDateString(site.startDate);
    8101159     
    8111160      var siteData = statistics[namePrefix];     
    8121161      var siteLatestDate = siteData['latestDateKey'];
    813       var siteLatestDateYear = siteLatestDate.substr(0,4);
    814       var siteLatestDateMonth = siteLatestDate.substr(4,2);
    815       var siteLatestDateDate = siteLatestDate.substr(6,2);
    816       var siteLatestDateStr = siteLatestDateYear + '-' + siteLatestDateMonth + '-' + siteLatestDateDate;
     1162      var siteLatestDateStr = addHyphensToDateString(siteLatestDate);
    8171163      var tableRow = document.createElement('tr');
    8181164      var tableCol = getTableCellElement(siteName, 'rowtitle');
    8191165      tableRow.appendChild(tableCol);
    820       tableRow.appendChild(getTableCellElement(year+'-'+(month)+'-'+date, 'reportdata'));
     1166      tableRow.appendChild(getTableCellElement(siteStartDateStr, 'reportdata'));
     1167      tableRow.appendChild(getTableCellElement(siteLatestDateStr, 'reportdata'));
     1168      var noDateKey = 'noDate';
     1169      var sumKey = 'sumKey';
     1170      var totalKey = 'totalKey';
     1171      if (siteData != null)
     1172      {
     1173        data = getJSONDataWithPercent(siteData, 'yesPatient', sumKey, numDecimals);
     1174        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1175        data = getJSONDataWithPercent(siteData, 'yesNoPatient', sumKey, numDecimals);
     1176        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1177        data = getJSONDataWithPercent(siteData, 'no', sumKey, numDecimals);
     1178        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1179        data = getJSONDataWithPercent(siteData, 'notAsked', sumKey, numDecimals);
     1180        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1181        data = getJSONDataWithPercent(siteData, noDateKey, sumKey, numDecimals);
     1182        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1183        // Add column with summed values for site
     1184        var siteSum = getJSONData(siteData, sumKey, 0);
     1185        tableRow.appendChild(getTableCellElement(siteSum, 'rowsummary'));
     1186      }
     1187      // Add column with total number of samples for site, regardless of creation date
     1188      var siteTotal = getJSONData(siteData, totalKey, 0);
     1189      tableRow.appendChild(getTableCellElement(siteTotal, 'rowsummary'));
     1190      reportTable.appendChild(tableRow);
     1191    }
     1192  }
     1193
     1194  function addDataRowsToConsentTableUnknownDate(report, reportTable, numDecimals)
     1195  {
     1196    var sites = report.sites;   
     1197    var statistics = report.statistics;
     1198    unknownCreation = statistics.noDate;
     1199    unknownSite = statistics.unknownSite;
     1200    var siteOrderList = report.siteOrderListKey;
     1201    for (var siteOrderIndex in siteOrderList)
     1202    {
     1203      var namePrefix = siteOrderList[siteOrderIndex];   
     1204      if (!sites.hasOwnProperty(namePrefix)) continue;       
     1205      var site = sites[namePrefix];
     1206      var siteName = site.name;
     1207      var siteStartDate = dateStrToDate(site.startDate);
     1208      var siteStartDateStr = addHyphensToDateString(site.startDate);
     1209     
     1210      var siteData = statistics[namePrefix];     
     1211      var siteLatestDate = siteData['latestDateKey'];
     1212      var siteLatestDateStr = addHyphensToDateString(siteLatestDate);
     1213      var tableRow = document.createElement('tr');
     1214      var tableCol = getTableCellElement(siteName, 'rowtitle');
     1215      tableRow.appendChild(tableCol);
     1216      tableRow.appendChild(getTableCellElement(siteStartDateStr, 'reportdata'));
     1217      tableRow.appendChild(getTableCellElement(siteLatestDateStr, 'reportdata'));
     1218      var noDateKey = 'noDate';
     1219      var sumKey = 'sumKey';
     1220      var totalKey = 'totalKey';
     1221      if (siteData != null)
     1222      {
     1223        data = getJSONDataWithPercent(siteData, 'yesNoDate', sumKey, numDecimals);
     1224        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1225        data = getJSONDataWithPercent(siteData, 'noNoDate', sumKey, numDecimals);
     1226        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1227        data = getJSONDataWithPercent(siteData, 'notAskedNoDate', sumKey, numDecimals);
     1228        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1229        data = getJSONDataWithPercent(siteData, 'missing', sumKey, numDecimals);
     1230        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1231        // Add column with summed values for site
     1232        var siteSum = getJSONData(siteData, noDateKey, 0);
     1233        tableRow.appendChild(getTableCellElement(siteSum, 'rowsummary'));
     1234      }
     1235      // Add column with total number of samples for site, regardless of creation date
     1236      var siteTotal = getJSONData(siteData, totalKey, 0);
     1237      tableRow.appendChild(getTableCellElement(siteTotal, 'rowsummary'));
     1238      reportTable.appendChild(tableRow);
     1239    }
     1240  }
     1241
     1242  function addDataRowsToOverviewTable(report, reportTable)
     1243  {
     1244    var sites = report.sites;   
     1245    var statistics = report.statistics;
     1246    unknownCreation = statistics.noDate;
     1247    unknownSite = statistics.unknownSite;
     1248    var siteOrderList = report.siteOrderListKey;
     1249    for (var siteOrderIndex in siteOrderList)
     1250    {
     1251      var namePrefix = siteOrderList[siteOrderIndex];   
     1252      if (!sites.hasOwnProperty(namePrefix)) continue;       
     1253      var site = sites[namePrefix];
     1254      var siteName = site.name;       
     1255      var siteStartDate = dateStrToDate(site.startDate);
     1256      var siteStartDateStr = addHyphensToDateString(site.startDate);
     1257     
     1258      var siteData = statistics[namePrefix];     
     1259      var siteLatestDate = siteData['latestDateKey'];
     1260      var siteLatestDateStr = addHyphensToDateString(siteLatestDate);
     1261      var tableRow = document.createElement('tr');
     1262      var tableCol = getTableCellElement(siteName, 'rowtitle');
     1263      tableRow.appendChild(tableCol);
     1264      tableRow.appendChild(getTableCellElement(siteStartDateStr, 'reportdata'));
     1265      tableRow.appendChild(getTableCellElement(siteLatestDateStr, 'reportdata'));
     1266      var noDateKey = 'noDate';
     1267      var sumKey = 'sumKey';
     1268      var totalKey = 'totalKey';
     1269      if (siteData != null)
     1270      {
     1271        data = getJSONData(siteData, 'patient');
     1272        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1273        data = getJSONData(siteData, 'bloodSample');
     1274        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1275        data = getJSONData(siteData, 'specimen');
     1276        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1277        data = getJSONData(siteData, 'noSpecimen');
     1278        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1279        data = getJSONData(siteData, 'consentYes');
     1280        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1281        data = getJSONData(siteData, 'consentMissing');
     1282        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1283      }
     1284      reportTable.appendChild(tableRow);
     1285    }
     1286  }
     1287
     1288  function addDataRowsToOverviewPatientDetailedTable(report, reportTable)
     1289  {
     1290    var sites = report.sites;   
     1291    var statistics = report.statistics;
     1292    unknownCreation = statistics.noDate;
     1293    unknownSite = statistics.unknownSite;
     1294    var siteOrderList = report.siteOrderListKey;
     1295    for (var siteOrderIndex in siteOrderList)
     1296    {
     1297      var namePrefix = siteOrderList[siteOrderIndex];   
     1298      if (!sites.hasOwnProperty(namePrefix)) continue;       
     1299      var site = sites[namePrefix];
     1300      var siteName = site.name;       
     1301      var siteStartDate = dateStrToDate(site.startDate);
     1302      var siteStartDateStr = addHyphensToDateString(site.startDate);
     1303     
     1304      var siteData = statistics[namePrefix];
     1305/*   
     1306      var siteLatestDate = siteData['latestDateKey'];
     1307      var siteLatestDateStr = addHyphensToDateString(siteLatestDate);
     1308*/
     1309      var tableRow = document.createElement('tr');
     1310      var tableCol = getTableCellElement(siteName, 'rowtitle');
     1311      tableRow.appendChild(tableCol);
     1312      tableRow.appendChild(getTableCellElement(siteStartDateStr, 'reportdata'));
     1313/*
     1314      tableRow.appendChild(getTableCellElement(siteLatestDateStr, 'reportdata'));
     1315*/
     1316      var noDateKey = 'noDate';
     1317      var sumKey = 'sumKey';
     1318      var totalKey = 'totalKey';
     1319      if (siteData != null)
     1320      {
     1321        data = getJSONData(siteData, 'patientBloodSampleOnly');
     1322        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1323        data = getJSONData(siteData, 'patientSpecimenOnly');
     1324        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1325        data = getJSONData(siteData, 'patientNoSpecimenOnly');
     1326        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1327        data = getJSONData(siteData, 'patientBloodSampleAndSpecimen');
     1328        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1329        data = getJSONData(siteData, 'patientBloodSampleAndNoSpecimen');
     1330        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1331        data = getJSONData(siteData, 'patientSpecimenAndNoSpecimen');
     1332        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1333        data = getJSONData(siteData, 'patientBloodSampleAndSpecimenAndNoSpecimen');
     1334        tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1335        //data = getJSONData(siteData, 'patientNoSamples');
     1336        //tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1337        data = getJSONData(siteData, 'sumKey');
     1338        tableRow.appendChild(getTableCellElement(data, 'rowsummary'));
     1339      }
     1340      reportTable.appendChild(tableRow);
     1341    }
     1342  }
     1343
     1344  function addDataRowsToMissingSampleDataTable(report, reportTable)
     1345  {
     1346    var sites = report.sites;   
     1347    var statistics = report.statistics;
     1348    var sampleType = report.sampleType;
     1349    var permissionDeniedForPatientName = report.permissionDeniedForPatientName;
     1350    var unknownCreation = statistics.noDate;
     1351    var unknownSite = statistics.unknownSite;
     1352    var siteOrderList = report.siteOrderListKey;
     1353    for (var siteOrderIndex in siteOrderList)
     1354    {
     1355      var namePrefix = siteOrderList[siteOrderIndex];   
     1356      if (!sites.hasOwnProperty(namePrefix)) continue;       
     1357      var site = sites[namePrefix];
     1358      var siteName = site.name;
     1359      var siteStartDate = dateStrToDate(site.startDate);
     1360      var siteStartDateStr = addHyphensToDateString(site.startDate);
     1361     
     1362      var siteData = statistics[namePrefix];     
     1363      var siteLatestDate = siteData['latestDateKey'];
     1364      var siteLatestDateStr = addHyphensToDateString(siteLatestDate);
     1365      var tableRow = document.createElement('tr');
     1366      var tableCol = getTableCellElement(siteName, 'rowtitle');
     1367      tableRow.appendChild(tableCol);
     1368      tableRow.appendChild(getTableCellElement(siteStartDateStr, 'reportdata'));
    8211369      tableRow.appendChild(getTableCellElement(siteLatestDateStr, 'reportdata'));
    8221370      //var currentDate = new Date(periodStartDate.getFullYear(), periodStartDate.getMonth(), periodStartDate.getDate());     
     
    8261374      if (siteData != null)
    8271375      {
    828         data = getJSONDataWithPercent(siteData, 'yesPatient', sumKey, numDecimals);
    829         tableRow.appendChild(getTableCellElement(data, 'reportdata'));
    830         data = getJSONDataWithPercent(siteData, 'yesNoPatient', sumKey, numDecimals);
    831         tableRow.appendChild(getTableCellElement(data, 'reportdata'));
    832         data = getJSONDataWithPercent(siteData, 'no', sumKey, numDecimals);
    833         tableRow.appendChild(getTableCellElement(data, 'reportdata'));
    834         data = getJSONDataWithPercent(siteData, 'notAsked', sumKey, numDecimals);
    835         tableRow.appendChild(getTableCellElement(data, 'reportdata'));
    836         data = getJSONDataWithPercent(siteData, noDateKey, sumKey, numDecimals);
    837         tableRow.appendChild(getTableCellElement(data, 'reportdata'));
    838         // Add column with summed values for site
    839         var siteSum = getJSONData(siteData, sumKey, 0);
    840         tableRow.appendChild(getTableCellElement(siteSum, 'rowsummary'));
    841       }
    842       // Add column with total number of samples for site, regardless of creation date
    843       var siteTotal = getJSONData(siteData, totalKey, 0);
    844       tableRow.appendChild(getTableCellElement(siteTotal, 'rowsummary'));
    845       reportTable.appendChild(tableRow);
    846     }
    847   }
    848 
    849   function addDataRowsToConsentTableUnknownDate(report, reportTable, numDecimals)
    850   {
    851     var sites = report.sites;   
    852     var statistics = report.statistics;
    853     unknownCreation = statistics.noDate;
    854     unknownSite = statistics.unknownSite;
    855     var siteOrderList = report.siteOrderListKey;
    856     for (var siteOrderIndex in siteOrderList)
    857     {
    858       var namePrefix = siteOrderList[siteOrderIndex];   
    859       if (!sites.hasOwnProperty(namePrefix)) continue;       
    860       var site = sites[namePrefix];
    861       var siteName = site.name;
    862       var year = site.startDate.substr(0,4);
    863       var month = site.startDate.substr(5,2);
    864       var date = site.startDate.substr(8,2);     
    865       var siteStartDate = new Date(year, month-1, date);
    866      
    867       var siteData = statistics[namePrefix];     
    868       var siteLatestDate = siteData['latestDateKey'];
    869       var siteLatestDateYear = siteLatestDate.substr(0,4);
    870       var siteLatestDateMonth = siteLatestDate.substr(4,2);
    871       var siteLatestDateDate = siteLatestDate.substr(6,2);
    872       var siteLatestDateStr = siteLatestDateYear + '-' + siteLatestDateMonth + '-' + siteLatestDateDate;
    873       var tableRow = document.createElement('tr');
    874       var tableCol = getTableCellElement(siteName, 'rowtitle');
    875       tableRow.appendChild(tableCol);
    876       tableRow.appendChild(getTableCellElement(year+'-'+(month)+'-'+date, 'reportdata'));
    877       tableRow.appendChild(getTableCellElement(siteLatestDateStr, 'reportdata'));
    878       //var currentDate = new Date(periodStartDate.getFullYear(), periodStartDate.getMonth(), periodStartDate.getDate());     
    879       var noDateKey = 'noDate';
    880       var sumKey = 'sumKey';
    881       var totalKey = 'totalKey';
    882       if (siteData != null)
    883       {
    884         data = getJSONDataWithPercent(siteData, 'yesNoDate', sumKey, numDecimals);
    885         tableRow.appendChild(getTableCellElement(data, 'reportdata'));
    886         data = getJSONDataWithPercent(siteData, 'noNoDate', sumKey, numDecimals);
    887         tableRow.appendChild(getTableCellElement(data, 'reportdata'));
    888         data = getJSONDataWithPercent(siteData, 'notAskedNoDate', sumKey, numDecimals);
    889         tableRow.appendChild(getTableCellElement(data, 'reportdata'));
    890         data = getJSONDataWithPercent(siteData, 'missing', sumKey, numDecimals);
    891         tableRow.appendChild(getTableCellElement(data, 'reportdata'));
    892         // Add column with summed values for site
    893         var siteSum = getJSONData(siteData, noDateKey, 0);
    894         tableRow.appendChild(getTableCellElement(siteSum, 'rowsummary'));
    895       }
    896       // Add column with total number of samples for site, regardless of creation date
    897       var siteTotal = getJSONData(siteData, totalKey, 0);
    898       tableRow.appendChild(getTableCellElement(siteTotal, 'rowsummary'));
     1376        if ('false' == permissionDeniedForPatientName)
     1377        {
     1378          data = getJSONData(siteData, 'missingPatientName');
     1379          tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1380        }
     1381        else
     1382        {
     1383          data = '-';
     1384          tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1385        }
     1386        if (sampleType == 'specimen')
     1387        {
     1388          data = getJSONData(siteData, 'missingPadReference');
     1389          tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1390          data = getJSONData(siteData, 'missingLaterality');
     1391          tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1392          data = getJSONData(siteData, 'missingSamplingDateTime');
     1393          tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1394          data = getJSONData(siteData, 'missingRnaLaterDateTime');
     1395          tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1396        }
     1397        else if (sampleType == 'nospecimen')
     1398        {
     1399          data = getJSONData(siteData, 'missingSamplingDateTime');
     1400          tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1401        }
     1402        else if (sampleType == 'blood')
     1403        {
     1404          data = getJSONData(siteData, 'missingBloodSamplingDateTime');
     1405          tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1406          data = getJSONData(siteData, 'missingBloodFreezerDateTime');
     1407          tableRow.appendChild(getTableCellElement(data, 'reportdata'));
     1408        }
     1409      }
    8991410      reportTable.appendChild(tableRow);
    9001411    }
     
    11321643        siteLatestDateStr = siteLatestDateYear + '-' + siteLatestDateMonth + '-' + siteLatestDateDate;
    11331644      }
    1134 /*
    1135       var siteLatestDateYear = siteLatestDate.substr(0,4);
    1136       var siteLatestDateMonth = siteLatestDate.substr(4,2);
    1137       var siteLatestDateDate = siteLatestDate.substr(6,2);
    1138       var siteLatestDateStr = siteLatestDateYear + '-' + siteLatestDateMonth + '-' + siteLatestDateDate;
    1139 */
    11401645      var tableRow = document.createElement('tr');
    11411646      var tableCol = getTableCellElement(siteName, 'rowtitle');
     
    13261831  }
    13271832
     1833  /**
     1834   *  addHyphensToDateStr()
     1835   *
     1836   *  Adds hyphens to date string in yyyymmdd format to
     1837   *  get yyyy-mm-dd format. If input string already contains
     1838   *  hyphen(s), the input string is returned unchanged.
     1839   *  If input string is null or empty, '????-??-??' is returned.
     1840   *
     1841   *  @param dateStr String Input date string in yyyy-mm-dd or yyyymmdd format.
     1842   *  @return String Date string in yyyy-mm-dd format.
     1843   */
     1844  function addHyphensToDateString(dateStr)
     1845  {
     1846    var dateWithHyphensStr = '????-??-??';
     1847    if (dateStr != null && dateStr != '')
     1848    {
     1849      // Check if input string already contains hyphen
     1850      if (dateStr.indexOf("-") >= 0)
     1851      {
     1852        // Date already has hyphen(s)
     1853        dateWithHyphensStr = dateStr;
     1854      }
     1855      else
     1856      {
     1857        // Date in yyyymmdd format
     1858        var yearStr = dateStr.substr(0,4);
     1859        var monthStr = dateStr.substr(4,2);
     1860        var dayStr = dateStr.substr(6,2);     
     1861        dateWithHyphensStr = yearStr + '-' + monthStr + '-' + dayStr;
     1862      }
     1863    }
     1864    return dateWithHyphensStr;
     1865  }
     1866
     1867  /**
     1868   *  dateStrToDate()
     1869   *
     1870   *  Takes an input date string in yyyy-mm-dd or yyyymmdd format
     1871   *  and returns a date corresponding to the date string.
     1872   *  If input string is null or empty, null is returned.
     1873   *
     1874   *  @param dateStr String Input date string in yyyy-mm-dd or yyyymmdd format.
     1875   *  @return Date Date corresponding to input date string.
     1876   */
     1877  function dateStrToDate(dateStr)
     1878  {
     1879    var date = null;
     1880    if (dateStr != null && dateStr != '')
     1881    {
     1882      // Check if input string already contains hyphen
     1883      if (dateStr.indexOf("-") >= 0)
     1884      {
     1885        // Date in yyyy-mm-dd format
     1886        var yearStr = dateStr.substr(0,4);
     1887        var monthStr = dateStr.substr(5,2);
     1888        var dayStr = dateStr.substr(8,2);     
     1889        var date = new Date(parseInt(yearStr, 10), parseInt(monthStr, 10)-1, parseInt(dayStr, 10));
     1890      }
     1891      else
     1892      {
     1893        // Date in yyyymmdd format
     1894        var yearStr = dateStr.substr(0,4);
     1895        var monthStr = dateStr.substr(4,2);
     1896        var dayStr = dateStr.substr(6,2);     
     1897        var date = new Date(parseInt(yearStr, 10), parseInt(monthStr, 10)-1, parseInt(dayStr, 10));
     1898      }
     1899    }
     1900    return date;
     1901  }
     1902
    13281903  /*
    1329    * Get the ISO week number for a given date
     1904   *  Get the ISO week number for a given date
    13301905   *
    1331    * Based on code at http://stackoverflow.com/questions/6117814/get-week-of-year-in-javascript-like-in-php
     1906   *  Based on code at http://stackoverflow.com/questions/6117814/get-week-of-year-in-javascript-like-in-php
     1907   *
     1908   *  @param date String Input date to get ISO week number for.
     1909   *  @return int ISO week number for input date.
    13321910   */
    13331911  function getISOWeekNumber(date)
     
    13841962                <option value="consentcount">Consent count report</option>
    13851963                <option value="patientcount">Patient count report</option>
     1964                <option value="overviewreport">Overview report</option>
     1965                <option value="missingsampledatareport">Missing sample data report</option>
    13861966              </select>
    13871967            </td>
     
    14091989            <table border="0" cellspacing="0" cellpadding="0" width="100%">           
    14101990            <tr>
    1411               <td valign="top" class="prompt">Report period</td>
     1991              <td valign="top" class="prompt">
     1992                <div id="reportPeriodSubSection01" style="display:none;">
     1993                  <text id="reportPeriodSubSection01Header">Report period</text>
     1994                </div>
     1995              </td>
    14121996              <td valign="top" class="input">
    1413                 From<input type="text" onChange="dateOnChange()" size=7 name="fromdate"/>&nbsp;
    1414                 To<input type="text" onChange="dateOnChange()" size=7 name="todate" />
     1997                <div id="reportPeriodSubSection02" style="display:none;">
     1998                  From<input type="text" onChange="dateOnChange()" size=7 name="fromdate"/>&nbsp;
     1999                  To<input type="text" onChange="dateOnChange()" size=7 name="todate" />
     2000                </div>
    14152001              </td>
    14162002              <td valign="top" class="status" id="displayInterval.status"></td>
    14172003              <td class="help">
    1418                 <span id="displayInterval.message" class="message" style="display: none;"></span>
    1419                 Define which period the report should cover. Empty fields will include all <text id="items01">items</text>.<br>
     2004                <div id="reportPeriodSubSection04" style="display:none;">
     2005                  <span id="displayInterval.message" class="message" style="display: none;"></span>
     2006                  <!--
     2007                  Define which period the report should cover. Empty fields will include all <text id="items01">items</text>.<br>
     2008                  -->
     2009                  <text id="reportPeriodSubSection04HelpText">Parameter help text</text><br>
     2010                </div>
    14202011              </td>
    14212012            </tr>
     
    14612052                  <select name="sampletype">
    14622053                    <option value="specimen" selected="yes">Specimen</option>
     2054                    <option value="nospecimen">No specimen</option>
    14632055                    <option value="blood">Blood</option>
    14642056                  </select>
  • extensions/net.sf.basedb.reggie/branches/ticket-422/resources/specimentube.jsp

    r1726 r1782  
    613613      if (samplingTimestamp)
    614614      {
    615         if (rnaLaterTimestamp.getDate() == samplingTimestamp.getDate() && rnaLaterTimestamp.getTime()<samplingTimestamp.getTime())
    616         {
    617           setInputStatus('rnaLaterDate', 'RNA-later date+time must later then Sampling date+time','invalid');
    618           return;
    619         }
    620615        if (rnaLaterTimestamp.getDate() != samplingTimestamp.getDate())
    621616        {
    622617          setInputStatus('rnaLaterDate', 'Sampling and RNA later dates are different', 'invalid');
     618          return;
     619        }
     620        if (rnaLaterTimestamp.getTime() < samplingTimestamp.getTime())
     621        {
     622          setInputStatus('rnaLaterDate', 'RNA later time must be later than Sampling time','invalid');
    623623          return;
    624624        }
  • extensions/net.sf.basedb.reggie/branches/ticket-422/src/net/sf/basedb/reggie/Reggie.java

    r1757 r1782  
    3030    The current version of this package.
    3131  */
    32   public static final String VERSION = "2.10-dev";
     32  public static final String VERSION = "2.11-dev";
    3333
    3434 
  • extensions/net.sf.basedb.reggie/branches/ticket-422/src/net/sf/basedb/reggie/servlet/BloodRegistrationServlet.java

    r1757 r1782  
    1414import org.json.simple.parser.JSONParser;
    1515
    16 import net.sf.basedb.core.AnnotationSet;
    17 import net.sf.basedb.core.AnnotationType;
    1816import net.sf.basedb.core.Application;
    1917import net.sf.basedb.core.BioMaterialEvent;
     
    2422import net.sf.basedb.reggie.Reggie;
    2523import net.sf.basedb.reggie.Site;
     24import net.sf.basedb.reggie.converter.StringToDateConverter;
    2625import net.sf.basedb.reggie.dao.Annotationtype;
    2726import net.sf.basedb.reggie.dao.Blood;
     
    8786          blood.loadAnnotations(dc, "serum", Annotationtype.BLOOD_SERUM, null);
    8887          blood.loadAnnotations(dc, "bloodSample", Annotationtype.BLOOD_SAMPLE, null);
     88          blood.loadAnnotations(dc, "otherPathNote", Annotationtype.OTHER_PATH_NOTE, null);
    8989
    9090          // Wrap what we have so far up into JSON objects
     
    204204        Date freezerDate = Reggie.CONVERTER_STRING_TO_DATETIME.convert((String)jsonBlood.get("freezerDate"));
    205205        String bloodSample = Values.getStringOrNull((String)jsonBlood.get("bloodSample"));
     206        String otherPathNote = Values.getStringOrNull((String)jsonBlood.get("otherPathNote"));
    206207       
    207208        creationEvent.setEventDate(samplingDate);
     
    210211        Annotationtype.BLOOD_SERUM.setAnnotationValue(dc, blood, jsonBlood.get("serum"));
    211212        Annotationtype.BLOOD_SAMPLE.setAnnotationValue(dc, blood, bloodSample);
     213        Annotationtype.OTHER_PATH_NOTE.setAnnotationValue(dc, blood, otherPathNote);
    212214
    213215        Number copyConsentId = (Number)jsonBlood.get("copyConsent");
     
    239241        Date freezerDate = Reggie.CONVERTER_STRING_TO_DATETIME.convert((String)jsonBlood.get("freezerDate"));
    240242        String bloodSample = Values.getStringOrNull((String)jsonBlood.get("bloodSample"));
     243        String otherPathNote = Values.getStringOrNull((String)jsonBlood.get("otherPathNote"));
    241244       
    242245        blood.getCreationEvent().setEventDate(samplingDate);
     
    246249        Annotationtype.BLOOD_SERUM.setAnnotationValue(dc, blood, jsonBlood.get("serum"));
    247250        Annotationtype.BLOOD_SAMPLE.setAnnotationValue(dc, blood, bloodSample);
     251        Annotationtype.OTHER_PATH_NOTE.setAnnotationValue(dc, blood, otherPathNote);
    248252
    249253        jsonMessages.add("Blood '" + blood.getName() + "' updated successfully.");
     
    288292      patient.setName((String)jsonPat.get("name"));
    289293      String pnr = (String)jsonPat.get("personalNumber");
    290       String dateOfBirth = (String)jsonPat.get("dateOfBirth");
    291       String gender = (String)jsonPat.get("gender");
    292      
    293       AnnotationType personalNumberType = Annotationtype.PERSONAL_NUMBER.load(dc);
    294       AnnotationType familyNameType = Annotationtype.FAMILY_NAME.load(dc);
    295       AnnotationType allFirstNamesType = Annotationtype.ALL_FIRST_NAMES.load(dc);
    296       AnnotationType genderType = Annotationtype.GENDER.load(dc);
    297       AnnotationType dateOfBirthType = Annotationtype.DATE_OF_BIRTH.load(dc);
    298      
    299       AnnotationSet as = patient.getAnnotationSet();
    300       as.getAnnotation(personalNumberType).setValue(pnr);
    301       as.getAnnotation(familyNameType).setValue((String)jsonPat.get("familyName"));
    302       as.getAnnotation(allFirstNamesType).setValue((String)jsonPat.get("allFirstNames"));
    303       if (gender != null) as.getAnnotation(genderType).setValue(gender);
    304       if (dateOfBirth != null)
    305       {
    306         SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    307         df.setLenient(false);
    308         as.getAnnotation(dateOfBirthType).setValue(df.parse(dateOfBirth));
    309       }
     294      StringToDateConverter dateConverter = new StringToDateConverter(new SimpleDateFormat("yyyy-MM-dd"));
     295      Date dateOfBirth = dateConverter.convert((String)jsonPat.get("dateOfBirth"));
     296      String gender = Values.getStringOrNull((String)jsonPat.get("gender"));
     297      String familyName = Values.getStringOrNull((String)jsonPat.get("familyName"));
     298      String allFirstNames = Values.getStringOrNull((String)jsonPat.get("allFirstNames"));
     299
     300      Annotationtype.PERSONAL_NUMBER.setAnnotationValue(dc, patient, pnr);
     301      Annotationtype.FAMILY_NAME.setAnnotationValue(dc, patient, familyName);
     302      Annotationtype.ALL_FIRST_NAMES.setAnnotationValue(dc, patient, allFirstNames);
     303      Annotationtype.GENDER.setAnnotationValue(dc, patient, gender);
     304      Annotationtype.DATE_OF_BIRTH.setAnnotationValue(dc, patient, dateOfBirth);
     305   
    310306      if (gender == null || dateOfBirth == null)
    311307      {
  • extensions/net.sf.basedb.reggie/branches/ticket-422/src/net/sf/basedb/reggie/servlet/HistologyServlet.java

    r1695 r1782  
    77import java.util.Set;
    88import java.util.TreeSet;
    9 import java.util.regex.Matcher;
    10 import java.util.regex.Pattern;
    119
    1210import javax.servlet.ServletException;
     
    209207        ReactionPlate paraffinBlock = ReactionPlate.getById(dc, bioPlateId, BioplateType.PARAFFIN_BLOCK);
    210208        paraffinBlock.loadBioWells(dc, true);
     209        paraffinBlock.setAnnotation("comment", paraffinBlock.getBioPlate().getDescription());
    211210       
    212211        // Load child HEglass plates
    213212        List<ReactionPlate> heGlassPlates = paraffinBlock.findChildPlates(dc, BioplateType.HE_GLASS);
    214        
    215         Pattern storagePattern = Pattern.compile("Stored in glass box\\: (\\d+)\\; position\\: (\\d+)");
    216        
     213               
    217214        if (heGlassPlates.size() > 0)
    218215        {
     
    220217          for (ReactionPlate heGlass : heGlassPlates)
    221218          {
     219            BioPlate hePlate = heGlass.getBioPlate();
    222220            heGlass.loadBioWells(dc, true);
    223221            heGlass.loadBioMaterialAnnotations(dc, "GoodStain", Annotationtype.GOOD_STAIN, null);
    224            
    225             BioPlate hePlate = heGlass.getBioPlate();
    226            
    227             if (hePlate.getDescription() != null)
     222            heGlass.setAnnotation("comment", hePlate.getDescription());
     223           
     224            if (hePlate.getTray() != null && hePlate.getPosition() != null)
    228225            {
    229               Matcher m = storagePattern.matcher(hePlate.getDescription());
    230               if (m.matches())
    231               {
    232                 heGlass.setAnnotation("storageBox", m.group(1));
    233                 heGlass.setAnnotation("position", m.group(2));
    234               }
     226              heGlass.setAnnotation("storageBox", hePlate.getTray());
     227              heGlass.setAnnotation("position", hePlate.getPosition());
    235228            }
    236229           
     
    257250        {
    258251          BioPlate heGlass = result.get(0);
    259           if (heGlass.getDescription() != null)
    260           {
    261             Pattern storagePattern = Pattern.compile("Stored in glass box\\: (\\d+)\\; position\\: (\\d+)");
    262             Matcher m = storagePattern.matcher(heGlass.getDescription());
    263             if (m.matches())
    264             {
    265               json.put("storageBox", Integer.parseInt(m.group(1)));
    266               json.put("position", Integer.parseInt(m.group(2)));
    267             }
     252          if (heGlass.getTray() != null && heGlass.getPosition() != null)
     253          {
     254            json.put("storageBox", Values.getInt(heGlass.getTray()));
     255            json.put("position", Values.getInt(heGlass.getPosition()));
    268256          }
    269257        }
     
    406394        Date moveDate = Reggie.CONVERTER_STRING_TO_DATE.convert((String)jsonReq.get("moveDate"));
    407395        Number protocolId = (Number)jsonReq.get("protocolId");
    408         String storageBox = "";
     396        String storageBox = null;
    409397       
    410398        dc = sc.newDbControl();
     
    456444          {
    457445            JSONObject jsonBlock = (JSONObject)jsonBlocks.get(blockNo);
    458             storageBox = (String)jsonBlock.get("storageBox");
     446            storageBox = Values.getStringOrNull((String)jsonBlock.get("storageBox"));
    459447            Number blockId = (Number)jsonBlock.get("id");
    460448            blockPos = 0;
     
    463451            paraffinBlock = BioPlate.getById(dc, blockId.intValue());
    464452            paraffinBlock.setEventDate(moveDate);
    465             paraffinBlock.setDescription("Stored in block box: " + storageBox);
     453            paraffinBlock.setTray(storageBox);
     454            paraffinBlock.setDescription(Values.getStringOrNull((String)jsonBlock.get("comment")));
    466455           
    467456            // Attach the new paraffin block to the PLACE-ON-PLATE event
     
    471460            int numSamples = remainingBioMaterial > Histology.SAMPLES_PER_BLOCK ? Histology.SAMPLES_PER_BLOCK : remainingBioMaterial;
    472461           
    473             jsonMessages.add("Moved " + numSamples + " samples to '" + paraffinBlock.getName() + "' (" + paraffinBlock.getDescription() + ")");
     462            jsonMessages.add("Moved " + numSamples + " samples to '" + paraffinBlock.getName() + "'");
    474463          }
    475464         
     
    495484        // Mark the work list as removed
    496485        workList.setRemoved(true);
    497         sc.setUserClientSetting("net.sf.basedb.reggie.histology.last-block-box", storageBox);
     486        if (storageBox != null)
     487        {
     488          sc.setUserClientSetting("net.sf.basedb.reggie.histology.last-block-box", storageBox);
     489        }
    498490
    499491        dc.commit();
     
    516508        // and find the max "goodStain" value
    517509        BioPlate pb = BioPlate.getById(dc, plateId.intValue());
    518         int maxGoodStain = 1;
     510        pb.setDescription(Values.getStringOrNull((String)jsonPlate.get("comment")));
     511        int numHeGlass = jsonHeGlass.size();
    519512        for (int i = 0; i < jsonWells.size(); ++i)
    520513        {
     
    527520          {
    528521            jsonWell.put("histology", histology);
    529             Number goodStain = (Number)jsonWell.get("GoodStain");
    530             if (goodStain.intValue() > maxGoodStain)
    531             {
    532               maxGoodStain = goodStain.intValue();
    533             }
    534522          }
    535523        }
     
    547535        // Create required number of child glass plates
    548536        int numNewHEGlass = 0;
    549         for (int stainNo = 1; stainNo <= maxGoodStain; ++stainNo)
     537        for (int stainNo = 1; stainNo <= numHeGlass; ++stainNo)
    550538        {
    551539          JSONObject jsonGlass = (JSONObject)jsonHeGlass.get(stainNo-1);
    552           String storageBox = (String)jsonGlass.get("storageBox");
    553           String position = (String)jsonGlass.get("position");
     540          String storageBox = Values.getStringOrNull((String)jsonGlass.get("storageBox"));
     541          String position = Values.getStringOrNull((String)jsonGlass.get("position"));
     542          String comment = Values.getStringOrNull((String)jsonGlass.get("comment"));
    554543         
    555544          // Try to find an existing HE glass
     
    575564          }
    576565         
    577           heGlass.setDescription("Stored in glass box: " + storageBox + "; position: " + position);
     566          heGlass.setTray(storageBox);
     567          heGlass.setPosition(position);
     568          heGlass.setDescription(comment);
    578569         
    579570          int numGoodStains = 0;
     
    628619          if (hePlate == null)
    629620          {
    630             jsonMessages.add("Created '" + heGlass.getName() + "' with " +  numGoodStains + " good stains. (" + heGlass.getDescription() + ")");
     621            jsonMessages.add("Created '" + heGlass.getName() + "' with " +  numGoodStains + " good stains.");
    631622          }
    632623          else
  • extensions/net.sf.basedb.reggie/branches/ticket-422/src/net/sf/basedb/reggie/servlet/InstallServlet.java

    r1746 r1782  
    237237            Annotationtype.CONSENT, Annotationtype.CONSENT_DATE,
    238238            Annotationtype.BLOOD_SAMPLING_DATETIME, Annotationtype.BLOOD_FREEZER_DATETIME,
    239             Annotationtype.BLOOD_SERUM, Annotationtype.BLOOD_SAMPLE));
     239            Annotationtype.BLOOD_SERUM, Annotationtype.BLOOD_SAMPLE,
     240            Annotationtype.OTHER_PATH_NOTE));
    240241       
    241242        jsonChecks.add(checkAnnotationTypeCategory(dc, Subtype.SPECIMEN, createIfMissing,
  • extensions/net.sf.basedb.reggie/branches/ticket-422/src/net/sf/basedb/reggie/servlet/PersonalRegistrationServlet.java

    r1677 r1782  
    2626import net.sf.basedb.reggie.Reggie;
    2727import net.sf.basedb.reggie.Site;
     28import net.sf.basedb.reggie.converter.StringToDateConverter;
    2829import net.sf.basedb.reggie.dao.Annotationtype;
    2930import net.sf.basedb.reggie.dao.Blood;
     
    543544    Number patientId = (Number)jsonPat.get("id");
    544545    BioSource patient = null;
    545     AnnotationType familyNameType = Annotationtype.FAMILY_NAME.load(dc);
    546     AnnotationType allFirstNamesType = Annotationtype.ALL_FIRST_NAMES.load(dc);
    547    
     546    String familyName = Values.getStringOrNull((String)jsonPat.get("familyName"));
     547    String allFirstNames = Values.getStringOrNull((String)jsonPat.get("allFirstNames"));
    548548    if (patientId != null)
    549549    {
    550550      patient = BioSource.getById(dc, patientId.intValue());
    551551      // Update names
    552       AnnotationSet as = patient.getAnnotationSet();
    553       as.getAnnotation(familyNameType).setValue((String)jsonPat.get("familyName"));
    554       as.getAnnotation(allFirstNamesType).setValue((String)jsonPat.get("allFirstNames"));
     552      Annotationtype.FAMILY_NAME.setAnnotationValue(dc, patient, familyName);
     553      Annotationtype.ALL_FIRST_NAMES.setAnnotationValue(dc, patient, allFirstNames);
    555554    }
    556555    else
     
    561560      patient.setName((String)jsonPat.get("name"));
    562561      String pnr = (String)jsonPat.get("personalNumber");
    563       String dateOfBirth = (String)jsonPat.get("dateOfBirth");
    564       String gender = (String)jsonPat.get("gender");
    565      
    566       AnnotationType personalNumberType = Annotationtype.PERSONAL_NUMBER.load(dc);
    567       AnnotationType genderType = Annotationtype.GENDER.load(dc);
    568       AnnotationType dateOfBirthType = Annotationtype.DATE_OF_BIRTH.load(dc);
    569      
    570       AnnotationSet as = patient.getAnnotationSet();
    571       as.getAnnotation(personalNumberType).setValue(pnr);
    572       as.getAnnotation(familyNameType).setValue((String)jsonPat.get("familyName"));
    573       as.getAnnotation(allFirstNamesType).setValue((String)jsonPat.get("allFirstNames"));
    574       if (gender != null) as.getAnnotation(genderType).setValue(gender);
    575       if (dateOfBirth != null)
    576       {
    577         SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    578         df.setLenient(false);
    579         as.getAnnotation(dateOfBirthType).setValue(df.parse(dateOfBirth));
    580       }
     562      StringToDateConverter dateConverter = new StringToDateConverter(new SimpleDateFormat("yyyy-MM-dd"));
     563      Date dateOfBirth = dateConverter.convert((String)jsonPat.get("dateOfBirth"));
     564      String gender = Values.getStringOrNull((String)jsonPat.get("gender"));
     565     
     566      Annotationtype.PERSONAL_NUMBER.setAnnotationValue(dc, patient, pnr);
     567      Annotationtype.FAMILY_NAME.setAnnotationValue(dc, patient, familyName);
     568      Annotationtype.ALL_FIRST_NAMES.setAnnotationValue(dc, patient, allFirstNames);
     569      Annotationtype.GENDER.setAnnotationValue(dc, patient, gender);
     570      Annotationtype.DATE_OF_BIRTH.setAnnotationValue(dc, patient, dateOfBirth);
     571     
    581572      if (gender == null || dateOfBirth == null)
    582573      {
  • extensions/net.sf.basedb.reggie/branches/ticket-422/src/net/sf/basedb/reggie/servlet/SampleReportServlet.java

    r1757 r1782  
    2727import net.sf.basedb.core.ItemSubtype;
    2828import net.sf.basedb.core.MeasuredBioMaterial;
     29import net.sf.basedb.core.PermissionDeniedException;
    2930import net.sf.basedb.core.Sample;
    3031import net.sf.basedb.core.SessionControl;
     
    196197        json = createPatientCountReport(dc, json, startDate, endDate, viewType);
    197198      }
     199      else if ("overviewreport".equals(cmd))
     200      {
     201        String startDateParameter = Values.getString(req.getParameter("fdate"), null);
     202        String endDateParameter = Values.getString(req.getParameter("tdate"), null);
     203
     204        Date startDate = Reggie.CONVERTER_STRING_TO_DATE.convert(startDateParameter);
     205        Date endDate = Reggie.CONVERTER_STRING_TO_DATE.convert(endDateParameter);
     206       
     207        if (startDate == null)
     208        {
     209          // Get the when the first site started
     210          for (Site s : Site.getAllSites())
     211          {
     212            Date siteDate = Reggie.CONVERTER_STRING_TO_DATE.convert(s.getStartDate().replaceAll("-", ""));
     213            if (siteDate != null && (startDate == null || startDate.after(siteDate)))
     214            {
     215              startDate = siteDate;           
     216            }
     217          }
     218        }
     219        if (endDate == null)
     220        {
     221          // Get the date for today
     222          endDate = new Date();
     223        }
     224
     225        json = createOverviewReport(dc, json, startDate, endDate);
     226      }
     227      else if ("missingsampledatareport".equals(cmd))
     228      {
     229        String startDateParameter = Values.getString(req.getParameter("fdate"), null);
     230        String endDateParameter = Values.getString(req.getParameter("tdate"), null);
     231
     232        Date startDate = Reggie.CONVERTER_STRING_TO_DATE.convert(startDateParameter);
     233        Date endDate = Reggie.CONVERTER_STRING_TO_DATE.convert(endDateParameter);
     234       
     235        if (startDate == null)
     236        {
     237          // Get the when the first site started
     238          for (Site s : Site.getAllSites())
     239          {
     240            Date siteDate = Reggie.CONVERTER_STRING_TO_DATE.convert(s.getStartDate().replaceAll("-", ""));
     241            if (siteDate != null && (startDate == null || startDate.after(siteDate)))
     242            {
     243              startDate = siteDate;           
     244            }
     245          }
     246        }
     247        if (endDate == null)
     248        {
     249          // Get the date for today
     250          endDate = new Date();
     251        }
     252
     253        String sampleType = "specimen";
     254        String sampleTypeParameter = Values.getString(req.getParameter("stype"), null);
     255        if (sampleTypeParameter != null)
     256        {
     257          sampleType = sampleTypeParameter;
     258        }
     259
     260        json = createMissingSampleDataReport(dc, json, startDate, endDate, sampleType);
     261      }
    198262    }
    199263    catch (Throwable t)
     
    222286    ItemQuery<Sample> sampleQuery = Sample.getQuery();
    223287    sampleQuery.joinPermanent(Hql.innerJoin(null, "creationEvent", "ce", true));
    224     if (sampleType.equals("blood"))
     288    if (sampleType.equals("nospecimen"))
     289    {
     290      Subtype.NO_SPECIMEN.addFilter(dc, sampleQuery);
     291    }
     292    else if (sampleType.equals("blood"))
    225293    {
    226294      Subtype.BLOOD.addFilter(dc, sampleQuery);
     
    643711  }
    644712
     713  @SuppressWarnings({ "unchecked", "rawtypes" })
     714  private JSONObject createOverviewReport(DbControl dc, JSONObject json, Date startDate, Date endDate)
     715      throws ServletException, IOException
     716  {
     717    JSONObject jsonReport = new JSONObject();
     718    jsonReport.put("sites", getJSONSites());
     719   
     720    ItemQuery<Sample> sampleQuery = Sample.getQuery();
     721    sampleQuery.joinPermanent(Hql.innerJoin(null, "creationEvent", "ce", true));
     722    // ...only include 'Specimen', 'No Specimen', 'Blood', or 'Case' items
     723    sampleQuery.restrict(
     724      Restrictions.or(
     725        Subtype.SPECIMEN.restriction(dc, null),
     726        Subtype.NO_SPECIMEN.restriction(dc, null),
     727        Subtype.BLOOD.restriction(dc, null),
     728        Subtype.CASE.restriction(dc, null)
     729      ));
     730    sampleQuery.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
     731    sampleQuery.order(Orders.asc(Hql.property("name")));
     732    sampleQuery.order(Orders.asc(Hql.property("ce", "eventDate")));
     733    sampleQuery.setCacheResult(true);
     734    ItemResultIterator<Sample> sampleIterator = sampleQuery.iterate(dc);       
     735    // Use stored annotation snapshots for performance reasons
     736    SnapshotManager manager = new SnapshotManager();       
     737
     738    JSONObject jsonStatistics = new JSONObject();
     739    JSONObject jsonSitesCombined = new JSONObject();
     740    String patientKey = "patient";
     741    String bloodSampleKey = "bloodSample";
     742    String specimenKey = "specimen";
     743    String noSpecimenKey = "noSpecimen";
     744    String patientBloodSampleOnlyKey = "patientBloodSampleOnly";
     745    String patientSpecimenOnlyKey = "patientSpecimenOnly";
     746    String patientNoSpecimenOnlyKey = "patientNoSpecimenOnly";
     747    String patientBloodSampleAndSpecimenKey = "patientBloodSampleAndSpecimen";
     748    String patientBloodSampleAndNoSpecimenKey = "patientBloodSampleAndNoSpecimen";
     749    String patientSpecimenAndNoSpecimenKey = "patientSpecimenAndNoSpecimen";
     750    String patientBloodSampleAndSpecimenAndNoSpecimenKey = "patientBloodSampleAndSpecimenAndNoSpecimen";
     751    String patientNoSamplesKey = "patientNoSamples";
     752    String consentYesKey = "consentYes";
     753    String consentMissingKey = "consentMissing";
     754    String sitesCombinedKey = "sitesCombinedKey";
     755    String sumKey = "sumKey";
     756    String latestDateKey = "latestDateKey";
     757    String duplicateKey = "duplicateKey";
     758    jsonStatistics.put(sitesCombinedKey, jsonSitesCombined);
     759    // Initialize site data to 0 for the different keys
     760    jsonStatistics = initializeJSONSiteData(jsonStatistics, patientKey);
     761    jsonStatistics = initializeJSONSiteData(jsonStatistics, bloodSampleKey);
     762    jsonStatistics = initializeJSONSiteData(jsonStatistics, specimenKey);
     763    jsonStatistics = initializeJSONSiteData(jsonStatistics, noSpecimenKey);
     764    jsonStatistics = initializeJSONSiteData(jsonStatistics, patientBloodSampleOnlyKey);
     765    jsonStatistics = initializeJSONSiteData(jsonStatistics, patientSpecimenOnlyKey);
     766    jsonStatistics = initializeJSONSiteData(jsonStatistics, patientNoSpecimenOnlyKey);
     767    jsonStatistics = initializeJSONSiteData(jsonStatistics, patientBloodSampleAndSpecimenKey);
     768    jsonStatistics = initializeJSONSiteData(jsonStatistics, patientBloodSampleAndNoSpecimenKey);
     769    jsonStatistics = initializeJSONSiteData(jsonStatistics, patientSpecimenAndNoSpecimenKey);
     770    jsonStatistics = initializeJSONSiteData(jsonStatistics, patientBloodSampleAndSpecimenAndNoSpecimenKey);
     771    jsonStatistics = initializeJSONSiteData(jsonStatistics, consentYesKey);
     772    jsonStatistics = initializeJSONSiteData(jsonStatistics, consentMissingKey);
     773    // Initialize combined data to 0 for the different keys
     774    jsonSitesCombined.put(patientKey, 0);
     775    jsonSitesCombined.put(bloodSampleKey, 0);
     776    jsonSitesCombined.put(specimenKey, 0);
     777    jsonSitesCombined.put(noSpecimenKey, 0);
     778    jsonSitesCombined.put(patientBloodSampleOnlyKey, 0);
     779    jsonSitesCombined.put(patientSpecimenOnlyKey, 0);
     780    jsonSitesCombined.put(patientNoSpecimenOnlyKey, 0);
     781    jsonSitesCombined.put(patientBloodSampleAndSpecimenKey, 0);
     782    jsonSitesCombined.put(patientBloodSampleAndNoSpecimenKey, 0);
     783    jsonSitesCombined.put(patientSpecimenAndNoSpecimenKey, 0);
     784    jsonSitesCombined.put(patientBloodSampleAndSpecimenAndNoSpecimenKey, 0);
     785    jsonSitesCombined.put(consentYesKey, 0);
     786    jsonSitesCombined.put(consentMissingKey, 0);
     787    jsonSitesCombined.put(patientNoSamplesKey, 0);
     788    // Initialize other data to 0 for different keys
     789    jsonStatistics.put(duplicateKey, 0);
     790    Date latestDate = null;
     791    // Create HashMap to keep track of processed dates for each patient
     792    HashMap<String, Set<Date>>patientDateSetHashMap = new HashMap<String, Set<Date>>();
     793    //JSONObject jsonPatientnamePatientid = new JSONObject();
     794    // HashMap of patient id's and site prefixes
     795    HashMap<String, String> patientHashMap = new HashMap<String, String>();
     796    // Set of patient id's for patients with blood samples
     797    Set<String> patientsWithBloodSamplesSet = new HashSet<String>();
     798    // Set of patient id's for patients with specimens
     799    Set<String> patientsWithSpecimensSet = new HashSet<String>();
     800    // Set of patient id's for patients with no specimens
     801    Set<String> patientsWithNoSpecimensSet = new HashSet<String>();
     802    // Create HashMap to keep track of latest item date for each site
     803    HashMap<String, Date> sitePrefixDateHashMap = new HashMap<String, Date>();
     804    // Get item subtype constants for later use
     805    ItemSubtype subtypeSpecimen = Subtype.SPECIMEN.load(dc);
     806    ItemSubtype subtypeNoSpecimen = Subtype.NO_SPECIMEN.load(dc);
     807    ItemSubtype subtypeBlood = Subtype.BLOOD.load(dc);
     808    ItemSubtype subtypeCase = Subtype.CASE.load(dc);
     809    //
     810    while (sampleIterator != null && sampleIterator.hasNext())
     811    {
     812      Sample s = sampleIterator.next();
     813      BioMaterialEvent creationEvent = s.getCreationEvent();
     814      Date creationDate = creationEvent.getEventDate();
     815
     816      // Find patient id
     817      BioMaterial patient = null;
     818      if (s.getItemSubtype().equals(subtypeBlood))
     819      {
     820        // The parent is the 'Patient' for blood samples and cases
     821        patient = s.getParent();
     822      }
     823      else if (s.getItemSubtype().equals(subtypeSpecimen) || s.getItemSubtype().equals(subtypeNoSpecimen))
     824      {
     825        // The grandparent is the 'Patient' for specimens and no specimens
     826        MeasuredBioMaterial parent = (MeasuredBioMaterial) s.getParent();
     827        if (parent != null)
     828        {
     829          patient = parent.getParent();
     830        }
     831      }
     832
     833      // Update statistics for specimens, blood samples, and consents
     834      Site site = Site.findByCaseName(s.getName());
     835      if (site == Site.UNKNOWN)
     836      {
     837        String key = "unknownSite";
     838        jsonStatistics = updateJSONObjectCounter(jsonStatistics, key);
     839      }
     840      else
     841      {
     842        // Get site info           
     843        JSONObject jsonSite = (JSONObject)jsonStatistics.get(site.getPrefix());
     844        if (jsonSite == null)
     845        {
     846          jsonSite = new JSONObject();
     847          jsonStatistics.put(site.getPrefix(), jsonSite);
     848        }
     849
     850        // Store patient data for later processing
     851        String patientId = null;
     852        if (patient != null)
     853        {
     854          patientId = patient.getName();
     855          if (patientId != null && !patientId.equals(""))
     856          {
     857            // Add patient id to patient HashMap for site
     858            patientHashMap.put(patientId, site.getPrefix());
     859
     860            if (s.getItemSubtype().equals(subtypeSpecimen))
     861            {
     862              // Add patient to patients with specimens set
     863              patientsWithSpecimensSet.add(patientId);
     864            }
     865
     866            if (s.getItemSubtype().equals(subtypeNoSpecimen))
     867            {
     868              // Add patient to patients with no specimens set
     869              patientsWithNoSpecimensSet.add(patientId);
     870            }
     871
     872            if (s.getItemSubtype().equals(subtypeBlood))
     873            {
     874              // Add patient to patients with blood samples set
     875              patientsWithBloodSamplesSet.add(patientId);
     876            }
     877          }
     878        }
     879
     880        // Update specimen data
     881        if (s.getItemSubtype().equals(subtypeSpecimen))
     882        {
     883          jsonSite = updateJSONObjectCounter(jsonSite, specimenKey);
     884          jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, specimenKey);
     885        }
     886        // Update no specimen data
     887        if (s.getItemSubtype().equals(subtypeNoSpecimen))
     888        {
     889          jsonSite = updateJSONObjectCounter(jsonSite, noSpecimenKey);
     890          jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, noSpecimenKey);
     891        }
     892        // Update blood sample data
     893        if (s.getItemSubtype().equals(subtypeBlood))
     894        {
     895          jsonSite = updateJSONObjectCounter(jsonSite, bloodSampleKey);
     896          jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, bloodSampleKey);
     897        }
     898
     899        // Keep track of latest item date for site
     900        if (creationDate != null)
     901        {
     902          Date siteLatestDate = sitePrefixDateHashMap.get(site.getPrefix());
     903          if (siteLatestDate == null || siteLatestDate.before(creationDate))
     904          {
     905            sitePrefixDateHashMap.put(site.getPrefix(), creationDate);
     906          }
     907          // Keep track of latest item date so far
     908          if (latestDate == null || latestDate.before(creationDate))
     909          {
     910            latestDate = creationDate;
     911          }
     912        }
     913
     914        // Process consents
     915        String consent = null;
     916        Date consentDate = null;
     917        if (s.getItemSubtype().equals(subtypeBlood) || s.getItemSubtype().equals(subtypeCase))
     918        {
     919          // Get consent
     920          consent = (String) Annotationtype.CONSENT.getAnnotationValue(dc, manager, s);
     921          // Get consent date
     922          consentDate = (Date) Annotationtype.CONSENT_DATE.getAnnotationValue(dc, manager, s);
     923
     924          String key = null;
     925          Boolean duplicate = false;
     926          if (consent != null)
     927          {
     928            if (consentDate != null)
     929            {
     930              // The parent is the 'Patient' for blood samples and cases
     931              patient = s.getParent();
     932
     933              // Check if a consent already exists for the same patient and date
     934              if (patient != null)
     935              {
     936                patientId = patient.getName();
     937                if (patientId != null && !patientId.equals(""))
     938                {
     939                  if (inStringDateSetHashMap(patientDateSetHashMap, patientId, consentDate))
     940                  {
     941                    duplicate = true;
     942                  }
     943                  else
     944                  {
     945                    patientDateSetHashMap = updateStringDateSetHashMap(patientDateSetHashMap, patientId, consentDate);
     946                  }
     947                }
     948              }
     949            }
     950            // Count approved consents, including consents without patient id (PAT#) or date
     951            if (consent.equals("Yes"))
     952            {
     953              key = consentYesKey;
     954              if (consentDate != null)
     955              {
     956                // Keep track of latest item date for site
     957                Date siteLatestDate = sitePrefixDateHashMap.get(site.getPrefix());
     958                if (siteLatestDate == null || siteLatestDate.before(consentDate))
     959                {
     960                  sitePrefixDateHashMap.put(site.getPrefix(), consentDate);
     961                }
     962                // Keep track of latest item date so far
     963                if (latestDate == null || latestDate.before(consentDate))
     964                {
     965                  latestDate = consentDate;
     966                }
     967              }
     968            }
     969          }
     970          else
     971          {
     972            key = consentMissingKey;
     973          }
     974          // Note that items with duplicate == false include missing consent items
     975          if (!duplicate)
     976          {
     977            if (key != null)
     978            {
     979              // Update consent counters
     980              jsonSite = updateJSONObjectCounter(jsonSite, key);
     981              jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, key);
     982            }
     983          }
     984          else
     985          {
     986            jsonStatistics = updateJSONObjectCounter(jsonStatistics, duplicateKey);
     987          }
     988        }
     989      }
     990    }
     991
     992    // Process patients
     993    for (String patId: patientHashMap.keySet())
     994    {
     995      if (patId != null && !patId.equals(""))
     996      {
     997        // Get site info
     998        String sitePrefix = patientHashMap.get(patId);
     999        JSONObject jsonSite = (JSONObject)jsonStatistics.get(sitePrefix);
     1000        if (jsonSite == null)
     1001        {
     1002          jsonSite = new JSONObject();
     1003          jsonStatistics.put(sitePrefix, jsonSite);
     1004        }
     1005        // Update patient data
     1006        jsonSite = updateJSONObjectCounter(jsonSite, patientKey);
     1007        jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, patientKey);
     1008        if (patientsWithSpecimensSet.contains(patId))
     1009        {
     1010          if (patientsWithNoSpecimensSet.contains(patId))
     1011          {
     1012            if (patientsWithBloodSamplesSet.contains(patId))
     1013            {
     1014              // Patient with both specimens, no specimens, and blood samples
     1015              jsonSite = updateJSONObjectCounter(jsonSite, patientBloodSampleAndSpecimenAndNoSpecimenKey);
     1016              jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, patientBloodSampleAndSpecimenAndNoSpecimenKey);
     1017            }
     1018            else
     1019            {
     1020              // Patient with both specimens and no specimens
     1021              jsonSite = updateJSONObjectCounter(jsonSite, patientSpecimenAndNoSpecimenKey);
     1022              jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, patientSpecimenAndNoSpecimenKey);
     1023            }
     1024          }
     1025          else
     1026          {
     1027            if (patientsWithBloodSamplesSet.contains(patId))
     1028            {
     1029              // Patient with both specimens and blood samples
     1030              jsonSite = updateJSONObjectCounter(jsonSite, patientBloodSampleAndSpecimenKey);
     1031              jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, patientBloodSampleAndSpecimenKey);
     1032            }
     1033            else
     1034            {
     1035              // Patient with specimens only
     1036              jsonSite = updateJSONObjectCounter(jsonSite, patientSpecimenOnlyKey);
     1037              jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, patientSpecimenOnlyKey);
     1038            }
     1039          }
     1040        }
     1041        else
     1042        {
     1043          if (patientsWithNoSpecimensSet.contains(patId))
     1044          {
     1045            if (patientsWithBloodSamplesSet.contains(patId))
     1046            {
     1047              // Patient with both blood samples and no specimens
     1048              jsonSite = updateJSONObjectCounter(jsonSite, patientBloodSampleAndNoSpecimenKey);
     1049              jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, patientBloodSampleAndNoSpecimenKey);
     1050            }
     1051            else
     1052            {
     1053              // Patient with no specimens only
     1054              jsonSite = updateJSONObjectCounter(jsonSite, patientNoSpecimenOnlyKey);
     1055              jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, patientNoSpecimenOnlyKey);
     1056            }
     1057          }
     1058          else
     1059          {
     1060            if (patientsWithBloodSamplesSet.contains(patId))
     1061            {
     1062              // Patient with blood samples only
     1063              jsonSite = updateJSONObjectCounter(jsonSite, patientBloodSampleOnlyKey);
     1064              jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, patientBloodSampleOnlyKey);
     1065            }
     1066            else
     1067            {
     1068              // Patient with no sample
     1069              jsonSite = updateJSONObjectCounter(jsonSite, patientNoSamplesKey);
     1070              jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, patientNoSamplesKey);
     1071            }
     1072          }
     1073        }
     1074        // Update summed patient data
     1075        jsonSite = updateJSONObjectCounter(jsonSite, sumKey);
     1076        jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, sumKey);
     1077      }
     1078    }
     1079
     1080    // Add latest item date for site to site JSON object
     1081    DateToStringConverter date2StringConverter = Reggie.CONVERTER_DATE_TO_STRING;
     1082    for (Site s: Site.getAllSites())
     1083    {
     1084      JSONObject jsonSite = (JSONObject) jsonStatistics.get(s.getPrefix());
     1085      if (jsonSite == null)
     1086      {
     1087        jsonSite = new JSONObject();
     1088        jsonStatistics.put(s.getPrefix(), jsonSite);
     1089      }
     1090      Date siteLatestDate = sitePrefixDateHashMap.get(s.getPrefix());
     1091      jsonSite.put(latestDateKey, date2StringConverter.convert(siteLatestDate));
     1092    }
     1093    // Add latest date for further transfer to other JSON object
     1094    jsonStatistics.put(latestDateKey, date2StringConverter.convert(latestDate));
     1095    // Add number of patients with no samples
     1096    Integer numPatientsNoSamples = (Integer) jsonSitesCombined.get(patientNoSamplesKey);
     1097    if (numPatientsNoSamples == null)
     1098    {
     1099      numPatientsNoSamples = 0;
     1100    }
     1101    jsonStatistics.put(patientNoSamplesKey, numPatientsNoSamples);
     1102    // Add number of patients with both specimens and no specimens
     1103    Integer numPatientsSpecimensAndNoSpecimens = (Integer) jsonSitesCombined.get(patientSpecimenAndNoSpecimenKey);
     1104    if (numPatientsSpecimensAndNoSpecimens == null)
     1105    {
     1106      numPatientsSpecimensAndNoSpecimens = 0;
     1107    }
     1108    jsonStatistics.put(patientSpecimenAndNoSpecimenKey, numPatientsSpecimensAndNoSpecimens);
     1109    // Add number of patients with both blood samples, specimens, and no specimens
     1110    Integer numPatientsBloodSamplesAndSpecimensAndNoSpecimens = (Integer) jsonSitesCombined.get(patientBloodSampleAndSpecimenAndNoSpecimenKey);
     1111    if (numPatientsBloodSamplesAndSpecimensAndNoSpecimens == null)
     1112    {
     1113      numPatientsBloodSamplesAndSpecimensAndNoSpecimens = 0;
     1114    }
     1115    jsonStatistics.put(patientBloodSampleAndSpecimenAndNoSpecimenKey, numPatientsBloodSamplesAndSpecimensAndNoSpecimens);
     1116    //
     1117    jsonReport.put("statistics", jsonStatistics);       
     1118    jsonReport.put("beginDate", date2StringConverter.convert(startDate));
     1119    jsonReport.put("endDate", date2StringConverter.convert(endDate));
     1120    // Transfer latest date from jsonStatistics to jsonReport
     1121    String latestDateStr = (String) jsonStatistics.get("latestDateKey");
     1122    jsonReport.put("latestDate", latestDateStr);
     1123    String siteOrder = alphabeticalOrder;
     1124    JSONObject jsonSiteOrderList = createJSONSiteOrderList(siteOrder);
     1125    jsonReport.put("siteOrderListKey", jsonSiteOrderList);
     1126    json.put("report", jsonReport);
     1127    return json;
     1128  }
     1129
     1130  @SuppressWarnings({ "unchecked", "rawtypes" })
     1131  private JSONObject createMissingSampleDataReport(DbControl dc, JSONObject json, Date startDate, Date endDate, String sampleType)
     1132      throws ServletException, IOException
     1133  {
     1134    JSONObject jsonReport = new JSONObject();
     1135    jsonReport.put("sites", getJSONSites());
     1136   
     1137    ItemQuery<Sample> sampleQuery = Sample.getQuery();
     1138    sampleQuery.joinPermanent(Hql.innerJoin(null, "creationEvent", "ce", true));
     1139    // Select what sample subtype to include in database search
     1140    if (sampleType.equals("nospecimen"))
     1141    {
     1142      Subtype.NO_SPECIMEN.addFilter(dc, sampleQuery);
     1143    }
     1144    else if (sampleType.equals("blood"))
     1145    {
     1146      Subtype.BLOOD.addFilter(dc, sampleQuery);
     1147    }
     1148    else
     1149    {
     1150      Subtype.SPECIMEN.addFilter(dc, sampleQuery);
     1151    }
     1152    sampleQuery.setIncludes(Reggie.INCLUDE_IN_CURRENT_PROJECT);
     1153    sampleQuery.order(Orders.asc(Hql.property("name")));
     1154    sampleQuery.order(Orders.asc(Hql.property("ce", "eventDate")));
     1155    sampleQuery.setCacheResult(true);
     1156    ItemResultIterator<Sample> sampleIterator = sampleQuery.iterate(dc);       
     1157    // Use stored annotation snapshots for performance reasons
     1158    SnapshotManager manager = new SnapshotManager();       
     1159
     1160    JSONObject jsonStatistics = new JSONObject();
     1161    JSONObject jsonSitesCombined = new JSONObject();
     1162    String missingPatientNameKey = "missingPatientName";
     1163    String missingPadReferenceKey = "missingPadReference";
     1164    String missingLateralityKey = "missingLaterality";
     1165    String missingSamplingDateTimeKey = "missingSamplingDateTime";
     1166    String missingRnaLaterDateTimeKey = "missingRnaLaterDateTime";
     1167    String missingBloodSamplingDateTimeKey = "missingBloodSamplingDateTime";
     1168    String missingBloodFreezerDateTimeKey = "missingBloodFreezerDateTime";
     1169    String permissionDeniedForPatientNameKey = "permissionDeniedForPatientName";
     1170    String sitesCombinedKey = "sitesCombinedKey";
     1171    String sumKey = "sumKey";
     1172    String latestDateKey = "latestDateKey";
     1173    String duplicateKey = "duplicateKey";
     1174    jsonStatistics.put(sitesCombinedKey, jsonSitesCombined);
     1175    // Initialize site data to 0 for the different keys
     1176    jsonStatistics = initializeJSONSiteData(jsonStatistics, missingPatientNameKey);
     1177    jsonStatistics = initializeJSONSiteData(jsonStatistics, missingPadReferenceKey);
     1178    jsonStatistics = initializeJSONSiteData(jsonStatistics, missingLateralityKey);
     1179    jsonStatistics = initializeJSONSiteData(jsonStatistics, missingSamplingDateTimeKey);
     1180    jsonStatistics = initializeJSONSiteData(jsonStatistics, missingRnaLaterDateTimeKey);
     1181    jsonStatistics = initializeJSONSiteData(jsonStatistics, missingBloodSamplingDateTimeKey);
     1182    jsonStatistics = initializeJSONSiteData(jsonStatistics, missingBloodFreezerDateTimeKey);
     1183    // Initialize combined data to 0 for the different keys
     1184    jsonSitesCombined.put(missingPatientNameKey, 0);
     1185    jsonSitesCombined.put(missingPadReferenceKey, 0);
     1186    jsonSitesCombined.put(missingLateralityKey, 0);
     1187    jsonSitesCombined.put(missingSamplingDateTimeKey, 0);
     1188    jsonSitesCombined.put(missingRnaLaterDateTimeKey, 0);
     1189    jsonSitesCombined.put(missingBloodSamplingDateTimeKey, 0);
     1190    jsonSitesCombined.put(missingBloodFreezerDateTimeKey, 0);
     1191    // Initialize other data to 0 for different keys
     1192    jsonStatistics.put(duplicateKey, 0);
     1193    Date latestDate = null;
     1194    // Create HashMap to keep track of latest item date for each site
     1195    HashMap<String, Date> sitePrefixDateHashMap = new HashMap<String, Date>();
     1196    // Get item subtype constants for later use
     1197    ItemSubtype subtypeSpecimen = Subtype.SPECIMEN.load(dc);
     1198    ItemSubtype subtypeNoSpecimen = Subtype.NO_SPECIMEN.load(dc);
     1199    ItemSubtype subtypeBlood = Subtype.BLOOD.load(dc);
     1200    Boolean permissionDeniedForPatientName = false;
     1201    //
     1202    while (sampleIterator != null && sampleIterator.hasNext())
     1203    {
     1204      Sample s = sampleIterator.next();
     1205      BioMaterialEvent creationEvent = s.getCreationEvent();
     1206      Date creationDate = creationEvent.getEventDate();
     1207
     1208      // Find patient id
     1209      BioMaterial patient = null;
     1210      if (s.getItemSubtype().equals(subtypeBlood))
     1211      {
     1212        // The parent is the 'Patient' for blood samples and cases
     1213        patient = s.getParent();
     1214      }
     1215      else if (s.getItemSubtype().equals(subtypeSpecimen) || s.getItemSubtype().equals(subtypeNoSpecimen))
     1216      {
     1217        // The grandparent is the 'Patient' for specimens and no specimens
     1218        MeasuredBioMaterial parent = (MeasuredBioMaterial) s.getParent();
     1219        if (parent != null)
     1220        {
     1221          patient = parent.getParent();
     1222        }
     1223      }
     1224
     1225      // Initialize sample data
     1226      String allFirstNames = null;
     1227      String familyName = null;
     1228      String pad = null;
     1229      String laterality = null;
     1230      Date samplingDate = null;
     1231      Date rnaLaterDate = null;
     1232      Date bloodSamplingDate = null;
     1233      Date bloodFreezerDate = null;
     1234
     1235      if (patient != null)
     1236      {
     1237        try
     1238        {
     1239          // Get patient all first names
     1240          allFirstNames = (String) Annotationtype.ALL_FIRST_NAMES.getAnnotationValue(dc, manager, patient);
     1241          // Get patient family name
     1242          familyName = (String) Annotationtype.FAMILY_NAME.getAnnotationValue(dc, manager, patient);
     1243        }
     1244        catch (PermissionDeniedException e)
     1245        {
     1246          permissionDeniedForPatientName = true;
     1247        }
     1248      }
     1249      if (sampleType.equals("specimen"))
     1250      {
     1251        // Get PAD reference
     1252        pad = (String) Annotationtype.PAD.getAnnotationValue(dc, manager, s);
     1253        // Get laterality
     1254        laterality = (String) Annotationtype.LATERALITY.getAnnotationValue(dc, manager, s);
     1255        // Get sampling date
     1256        samplingDate = (Date) Annotationtype.SAMPLING_DATETIME.getAnnotationValue(dc, manager, s);
     1257        // Get RNALater date
     1258        rnaLaterDate = (Date) Annotationtype.RNALATER_DATETIME.getAnnotationValue(dc, manager, s);
     1259      }
     1260      else if (sampleType.equals("nospecimen"))
     1261      {
     1262        // Get sampling date
     1263        samplingDate = (Date) Annotationtype.SAMPLING_DATETIME.getAnnotationValue(dc, manager, s);
     1264      }
     1265      else if (sampleType.equals("blood"))
     1266      {
     1267        // Get blood sampling date
     1268        bloodSamplingDate = (Date) Annotationtype.BLOOD_SAMPLING_DATETIME.getAnnotationValue(dc, manager, s);
     1269        // Get blood freezer date
     1270        bloodFreezerDate = (Date) Annotationtype.BLOOD_FREEZER_DATETIME.getAnnotationValue(dc, manager, s);
     1271      }
     1272      // Update statistics for sample type
     1273      Site site = Site.findByCaseName(s.getName());
     1274      if (site == Site.UNKNOWN)
     1275      {
     1276        String key = "unknownSite";
     1277        jsonStatistics = updateJSONObjectCounter(jsonStatistics, key);
     1278      }
     1279      else
     1280      {
     1281        // Get site info           
     1282        JSONObject jsonSite = (JSONObject)jsonStatistics.get(site.getPrefix());
     1283        if (jsonSite == null)
     1284        {
     1285          jsonSite = new JSONObject();
     1286          jsonStatistics.put(site.getPrefix(), jsonSite);
     1287        }
     1288
     1289        if (patient != null)
     1290        {
     1291          // Update missing first names data and family name data
     1292          if (allFirstNames == null || allFirstNames.equals("")
     1293              || familyName == null || familyName.equals(""))
     1294          {
     1295            // Update missing patient name data, provided the user has permission to check it
     1296            if (!permissionDeniedForPatientName)
     1297            {
     1298              jsonSite = updateJSONObjectCounter(jsonSite, missingPatientNameKey);
     1299              jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, missingPatientNameKey);
     1300            }
     1301          }
     1302        }
     1303        if (sampleType.equals("specimen"))
     1304        {
     1305          // Update missing PAD reference data
     1306          if (pad == null || pad.equals(""))
     1307          {
     1308            jsonSite = updateJSONObjectCounter(jsonSite, missingPadReferenceKey);
     1309            jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, missingPadReferenceKey);
     1310          }
     1311          // Update missing laterality data
     1312          if (laterality == null || laterality.equals(""))
     1313          {
     1314            jsonSite = updateJSONObjectCounter(jsonSite, missingLateralityKey);
     1315            jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, missingLateralityKey);
     1316          }
     1317          // Update missing sampling date data
     1318          if (samplingDate == null)
     1319          {
     1320            jsonSite = updateJSONObjectCounter(jsonSite, missingSamplingDateTimeKey);
     1321            jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, missingSamplingDateTimeKey);
     1322          }
     1323          // Update missing RNALater date data
     1324          if (rnaLaterDate == null)
     1325          {
     1326            jsonSite = updateJSONObjectCounter(jsonSite, missingRnaLaterDateTimeKey);
     1327            jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, missingRnaLaterDateTimeKey);
     1328          }
     1329        }
     1330        else if (sampleType.equals("nospecimen"))
     1331        {
     1332          // Update missing sampling date data
     1333          if (samplingDate == null)
     1334          {
     1335            jsonSite = updateJSONObjectCounter(jsonSite, missingSamplingDateTimeKey);
     1336            jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, missingSamplingDateTimeKey);
     1337          }
     1338        }
     1339        else if (sampleType.equals("blood"))
     1340        {
     1341          // Update missing blood sampling date data
     1342          if (bloodSamplingDate == null)
     1343          {
     1344            jsonSite = updateJSONObjectCounter(jsonSite, missingBloodSamplingDateTimeKey);
     1345            jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, missingBloodSamplingDateTimeKey);
     1346          }
     1347          // Update missing blood freezer date data
     1348          if (bloodFreezerDate == null)
     1349          {
     1350            jsonSite = updateJSONObjectCounter(jsonSite, missingBloodFreezerDateTimeKey);
     1351            jsonSitesCombined = updateJSONObjectCounter(jsonSitesCombined, missingBloodFreezerDateTimeKey);
     1352          }
     1353        }
     1354
     1355        // Keep track of latest item date for site
     1356        if (creationDate != null)
     1357        {
     1358          Date siteLatestDate = sitePrefixDateHashMap.get(site.getPrefix());
     1359          if (siteLatestDate == null || siteLatestDate.before(creationDate))
     1360          {
     1361            sitePrefixDateHashMap.put(site.getPrefix(), creationDate);
     1362          }
     1363          // Keep track of latest item date so far
     1364          if (latestDate == null || latestDate.before(creationDate))
     1365          {
     1366            latestDate = creationDate;
     1367          }
     1368        }
     1369      }
     1370    }
     1371    // Add latest item date for site to site JSON object
     1372    DateToStringConverter date2StringConverter = Reggie.CONVERTER_DATE_TO_STRING;
     1373    for (Site s: Site.getAllSites())
     1374    {
     1375      JSONObject jsonSite = (JSONObject) jsonStatistics.get(s.getPrefix());
     1376      if (jsonSite == null)
     1377      {
     1378        jsonSite = new JSONObject();
     1379        jsonStatistics.put(s.getPrefix(), jsonSite);
     1380      }
     1381      Date siteLatestDate = sitePrefixDateHashMap.get(s.getPrefix());
     1382      jsonSite.put(latestDateKey, date2StringConverter.convert(siteLatestDate));
     1383    }
     1384    // Add latest date for further transfer to other JSON object
     1385    jsonStatistics.put(latestDateKey, date2StringConverter.convert(latestDate));
     1386    //
     1387    jsonReport.put("statistics", jsonStatistics);       
     1388    jsonReport.put("sampleType", sampleType);
     1389    jsonReport.put("beginDate", date2StringConverter.convert(startDate));
     1390    jsonReport.put("endDate", date2StringConverter.convert(endDate));
     1391    // Transfer latest date from jsonStatistics to jsonReport
     1392    String latestDateStr = (String) jsonStatistics.get("latestDateKey");
     1393    jsonReport.put("latestDate", latestDateStr);
     1394    jsonReport.put(permissionDeniedForPatientNameKey, permissionDeniedForPatientName.toString());
     1395    String siteOrder = alphabeticalOrder;
     1396    JSONObject jsonSiteOrderList = createJSONSiteOrderList(siteOrder);
     1397    jsonReport.put("siteOrderListKey", jsonSiteOrderList);
     1398    json.put("report", jsonReport);
     1399    return json;
     1400  }
     1401
    6451402  private Boolean inStringDateSetHashMap(HashMap<String, Set<Date>> stringDateSetHashMap, String string, Date date)
    6461403  {
Note: See TracChangeset for help on using the changeset viewer.