Changeset 6277


Ignore:
Timestamp:
Jun 3, 2021, 3:46:36 PM (2 years ago)
Author:
Nicklas Nordborg
Message:

Merge Reggie 4.31.2 to the trunk.

Location:
extensions/net.sf.basedb.reggie/trunk
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • extensions/net.sf.basedb.reggie/trunk

  • extensions/net.sf.basedb.reggie/trunk/resources/index.jsp

    r6215 r6277  
    10761076              <ul>
    10771077              <li><span class="require-permission" data-role="PatientCurator" data-link="personal/generate-referral-forms.jsp?ID=<%=ID%>"
    1078                 >Generate referral forms</span>
     1078                >Referral ID generator</span>
    10791079              </ul>
    10801080            </dd>
  • extensions/net.sf.basedb.reggie/trunk/resources/personal/bloodform.js

    r3666 r6277  
    6666      return;
    6767    }
    68     var suffix = caseName.length > 7 ? caseName.substring(7, 8) : null;
    69     if (!Reggie.isValidCaseName(caseName, true) || suffix == 'D') // Allow 'C' suffix to be used
    70     {
    71       Wizard.setInputStatus('caseName', 'invalid', 'Only 7-digits name + optional \'C\' is allowed.');
     68    if (!Reggie.checkValidCaseName(caseName, 'K?', 'C?')) // Allow 'K'-prefix and/or 'C' suffix to be used
     69    {
     70      Wizard.setInputStatus('caseName', 'invalid', 'Expected 7-digits + optional \'K\' prefix or \'C\' suffix.');
    7271      frm.caseName.focus();
    7372      return;
     
    344343      // Select 'PreNeo' if case name has 'C' suffix
    345344      var caseName = frm.caseName.value;
    346       if (caseName.length > 7 && caseName.substring(7, 8) == 'C')
     345      var cLength = caseName.length;
     346      if (cLength > 7 && caseName.substr(cLength-1, 1) == 'C')
    347347      {
    348348        Forms.selectListOption(frm.bloodSample, 'PreNeo');
  • extensions/net.sf.basedb.reggie/trunk/resources/personal/generate-referral-forms.js

    r4083 r6277  
    1 var Istat = function()
     1var Xport = function()
    22{
    3   var istat = {};
     3  var xport = {};
    44  var debug = 0;
    55 
    6   var refStartScanbIdPure;
    7   var caseIsValid = false;
    8 
    9   istat.initPage = function()
     6  var siteIsValid = false;
     7  var startNumberIsValid = false;
     8  var numKitsIsValid = false;
     9
     10  xport.initPage = function()
    1011  {
    1112    // Step 1
    12     Events.addEventHandler('step-1', 'wizard-validate', istat.validateStep1);
    13     Events.addEventHandler('sites', 'change', istat.siteAndVariantOnChange);
    14     Events.addEventHandler('referralvariant', 'change', istat.siteAndVariantOnChange);
    15     Buttons.addClickHandler('gonext', Wizard.goNextOnClick);
    16    
    17     // Step 2
    18     Events.addEventHandler('step-2', 'wizard-validate', istat.validateStep2);
    19     Events.addEventHandler('caseName', 'keypress', Wizard.focusOnEnter);
    20     Events.addEventHandler('caseName', 'blur', istat.caseNameOnChange);
    21    
    22     // Step 3
    23     Buttons.addClickHandler('downloadformbatch1', istat.downloadFormBatch1);
    24     Buttons.addClickHandler('downloadformbatch2', istat.downloadFormBatch2);
    25     Buttons.addClickHandler('updateusedscanbidlist', istat.updateUsedScanbIdList);
     13    Events.addEventHandler('step-1', 'wizard-validate', xport.validateStep1);
     14    Events.addEventHandler('site', 'change', xport.siteOnChange);
     15    Events.addEventHandler('startNumber', 'blur', xport.startNumberOnChange);
     16    Events.addEventHandler('startNumber', 'keypress', Events.integerOnly);
     17    Events.addEventHandler('numKits', 'blur', xport.numKitsOnChange);
     18    Events.addEventHandler('numKits', 'keypress', Events.integerOnly);
     19    Events.addEventHandler('viewLogFile', 'click', xport.viewLogFile);
    2620   
    2721    // Navigation
    28     Buttons.addClickHandler('gocancel', Wizard.cancelWizard);
    2922    Buttons.addClickHandler('gorestart', Wizard.restartWizard);
     23    Buttons.addClickHandler('goregister', Wizard.goRegister);
     24    Buttons.addClickHandler('gopreview', xport.goPreview);
     25    Buttons.addClickHandler('viewLogFile2', xport.viewLogFile);
     26    Buttons.addClickHandler('godownload', xport.downloadBD47File);
     27   
     28    Events.addEventHandler('wizard', 'wizard-submit', xport.goExport);
    3029
    3130    Doc.show('step-1');
    32     Doc.show('gonext');
    33     Doc.addClass('gonext', 'disabled');
    34 
    35     refStartScanbIdPure = '';
     31    Wizard.setInputStatus('site', 'invalid');
     32    Wizard.setInputStatus('startNumber', 'invalid');
     33    Wizard.setInputStatus('numKits', 'invalid');
    3634
    3735    // Load sites
    3836    var frm = document.forms['reggie'];
    39     var url = '../ScanBQuarterMonthReport.servlet?ID='+App.getSessionId();
    40     url += '&cmd=GetSites';   
    41     Doc.addClass('sites', 'list-loading');
    42     frm.sites[0] = new Option('loading...');
    43     Wizard.asyncJsonRequest(url, istat.sitesLoaded);
    44   }
    45  
    46   istat.sitesLoaded = function(response)
    47   {
    48     Doc.removeClass('sites', 'list-loading');
     37    var url = '../ReferralGenerator.servlet?ID='+App.getSessionId();
     38    url += '&cmd=GetSitesAndStartNumber';   
     39    Doc.addClass('site', 'list-loading');
     40    frm.site[0] = new Option('loading...');
     41    Wizard.asyncJsonRequest(url, xport.sitesLoaded);
     42  }
     43 
     44  xport.sitesLoaded = function(response)
     45  {
     46    Doc.removeClass('site', 'list-loading');
    4947    var frm = document.forms['reggie'];
    5048    var sites = response.sites;
    51     frm.sites.length = 0;
    52     //frm.sites[0] = new Option('All sites together', '');
    53     frm.sites[0] = new Option('- Select site -', '');
     49    frm.site.length = 0;
     50    frm.site[0] = new Option('- Select site -', '');
    5451    for (var i = 0; i < sites.length; i++)
    5552    {
    5653      var s = sites[i];
    57       //var option = new Option(s.name, s.prefix);
    58       var option = new Option(s.name + '  [' + s.prefix + ']', s.prefix);
    59       frm.sites[frm.sites.length] = option;
    60     }
    61   }
    62 
    63   istat.siteAndVariantOnChange = function()
    64   {
    65     var frm = document.forms['reggie'];
    66     var site = frm.sites.value;
    67     var refVariant = frm.referralvariant.value;
    68     var siteAndVariantAreValid = false;
    69     if (site != '' && refVariant != '')
    70     {
    71       siteAndVariantAreValid = true;
    72     }
    73     if (siteAndVariantAreValid)
    74     {
    75       // Check if multiple template files for same referral from type
    76       var url = '../ReferralGenerator.servlet?ID='+App.getSessionId();
    77       url += '&cmd=GetReferralTemplateInfo';
    78       url += '&site='+encodeURIComponent(site);
    79       url += '&referralvariant='+encodeURIComponent(refVariant);
    80       Wizard.showLoadingAnimation('Getting referral template info...', 'ref-gen-progress');
    81       Wizard.asyncJsonRequest(url, istat.preValidateStep1);
     54      var option = new Option(s.name + ' [' + s.prefix + ']', s.prefix);
     55      frm.site[frm.site.length] = option;
     56    }
     57    frm.site.focus();
     58   
     59    frm.startNumber.value = response.lastReferralID || '';
     60    xport.startNumberOnChange();
     61   
     62    frm.numKits.value = response.lastNumKits || '25';
     63    xport.numKitsOnChange();
     64   
     65    if (response.logFile)
     66    {
     67      Doc.show('viewLogFile', 'inline');
     68      Data.set('viewLogFile', 'file-id', response.logFile);
     69    }
     70   
     71    Doc.show('gopreview');
     72    Doc.show('goregister');
     73  }
     74 
     75  xport.siteOnChange = function()
     76  {
     77    var frm = document.forms['reggie'];
     78    siteIsValid = false;
     79    Doc.element('sitePrefix').innerHTML = '00 -';
     80   
     81    if (frm.site.value == '')
     82    {
     83      Wizard.setInputStatus('site', 'invalid', 'Select a site');
     84      frm.site.focus();
     85      return;
     86    }
     87   
     88    Doc.element('sitePrefix').innerHTML = frm.site.value+' -';
     89    siteIsValid = true;
     90    Wizard.setInputStatus('site', 'valid');
     91    if (frm.startNumber.value == '')
     92    {
     93      frm.startNumber.focus();
    8294    }
    8395    else
    8496    {
    85       Doc.addClass('gonext', 'disabled');
    86     }
    87   }
    88 
    89   istat.preValidateStep1 = function(response)
    90   {
    91     var frm = document.forms['reggie'];
    92 
    93     var jsonMultTemplates = response.multTemplates;
    94     if (jsonMultTemplates.length > 0)
    95     {
    96       // List multiple templates/type
    97       //var html = '<table id="templateFilesTable" class="step-form">';
    98       var html = '<br>';
    99       html += '<table id="templateFilesTable">';
    100       // Header row
    101       html += '<tr>';
    102       html += '<th>Multiple template files for same type</th>';
    103       html += '<th>Template type</th>';
    104       html += '</tr>';
    105       // File list
    106       for (var i = 0; i < jsonMultTemplates.length; i++)
    107       {
    108         //var filename = jsonMultTemplates[i];
    109         var jsonMultTempl = jsonMultTemplates[i];
    110         var filename = jsonMultTempl['file'];
    111         var type = jsonMultTempl['type'];
    112         html += '<tr>';
    113         html += '<td>&nbsp;&nbsp;' + filename + '</td>';
    114         html += '<td>&nbsp;&nbsp;' + type + '</td>';
    115         html += '</tr>';
    116       }
    117       html += '</table>';
    118       Doc.element('step1message').innerHTML = html;
    119 
    120       // Display extra checkbox to confirm use of multiple templates/type
    121       var confirmMsg = 'Check to verify use of multiple template files for same type.';
    122       Wizard.showGoNextConfirmation(true, confirmMsg);
    123       return;
     97      frm.numKits.focus();
     98    }
     99  }
     100 
     101  xport.startNumberOnChange = function()
     102  {
     103    var frm = document.forms['reggie'];
     104    startNumberIsValid = false;
     105   
     106    var startNumber = frm.startNumber.value;
     107    if (startNumber == '')
     108    {
     109      Wizard.setInputStatus('startNumber', 'invalid', 'Missing');
     110      return;
     111    }
     112   
     113    if (!startNumber.match(/^\d{5}$/))
     114    {
     115      Wizard.setInputStatus('startNumber', 'invalid', 'It must be 5 digits.');
     116      return;
     117    }
     118   
     119    startNumberIsValid = true;
     120    Wizard.setInputStatus('startNumber', 'valid');
     121  }
     122 
     123  xport.numKitsOnChange = function()
     124  {
     125    var frm = document.forms['reggie'];
     126    numKitsIsValid = false;
     127   
     128    var numKits = frm.numKits.value;
     129    if (numKits == '')
     130    {
     131      Wizard.setInputStatus('numKits', 'invalid', 'Missing');
     132      return;
     133    }
     134   
     135    if (!numKits.match(/^\d+$/))
     136    {
     137      Wizard.setInputStatus('numKits', 'invalid', 'It must be a number.');
     138      return;
     139    }
     140   
     141    var nk = parseInt(numKits);
     142    if (nk < 1 || nk > 100)
     143    {
     144      Wizard.setInputStatus('numKits', 'invalid', 'It must be between 1 and 100');
     145      return;
     146    }
     147   
     148    numKitsIsValid = true;
     149    Wizard.setInputStatus('numKits', 'valid');
     150  }
     151
     152  xport.viewLogFile = function(event)
     153  {
     154    Dialogs.openPopup('', 'LogFile', 1050, 700);
     155    Files.viewFile(Data.get(event.currentTarget, 'file-id'), 'LogFile');
     156  }
     157
     158  xport.downloadBD47File = function(event)
     159  {
     160    var url = App.getRoot()+'filemanager/files/download/-'+App.getSessionId()+'-';
     161    url += Data.get(event.currentTarget, 'file-path');
     162    location.href = url;
     163  }
     164
     165  xport.validateStep1 = function(event)
     166  {
     167    var valid = siteIsValid;
     168    valid &= startNumberIsValid;
     169    valid &= numKitsIsValid;
     170    if (!valid) event.preventDefault();
     171  }
     172
     173  xport.goPreview = function()
     174  {
     175    if (!Wizard.validateCurrentStep()) return;
     176    xport.doExport(true);
     177  }
     178 
     179  xport.goExport = function()
     180  {
     181    xport.doExport(false);
     182  }
     183
     184  xport.doExport = function(preview)
     185  {
     186    var frm = document.forms['reggie'];
     187    var url = '../ReferralGenerator.servlet?ID='+App.getSessionId();
     188    url += '&cmd=ExportToBD47';
     189
     190    var submitInfo = {};
     191    submitInfo.site = frm.site.value;
     192    submitInfo.kitType = frm.kitType.value;
     193    submitInfo.startNumber = parseInt(frm.startNumber.value);
     194    submitInfo.numKits = parseInt(frm.numKits.value);
     195   
     196    Doc.hide('previewWrapper');
     197    if (preview)
     198    {
     199      url += '&preview=1';
     200      Wizard.asyncJsonRequest(url, xport.onPreviewLoaded, 'POST', JSON.stringify(submitInfo));
    124201    }
    125202    else
    126203    {
    127       Doc.removeClass('gonext', 'disabled');
    128     }
    129   }
    130 
    131   istat.validateStep1 = function(event)
    132   {
    133     istat.initializeStep2();
    134   }
    135 
    136   istat.initializeStep2 = function(response)
    137   {
    138     var frm = document.forms['reggie'];
    139     Wizard.setCurrentStep(2);
    140 
    141     istat.selectOptionsDisabled('sites', true);
    142     istat.selectOptionsDisabled('referralvariant', true);
    143 
    144     // Get referral start info
    145     var url = '../ReferralGenerator.servlet?ID='+App.getSessionId();
    146     url += '&cmd=GetReferralStartInfo';
    147     Wizard.showLoadingAnimation('Getting referral start info...', 'ref-gen-progress');
    148     Wizard.asyncJsonRequest(url, istat.initializeStep2a);
    149   }
    150    
    151   istat.initializeStep2a = function(response)
    152   {
    153     var frm = document.forms['reggie'];
    154 
    155     var jsonRefStartInfo = response.refStartInfo;
    156    
    157     var site = frm.sites.value;
    158     var refVariant = frm.referralvariant.value;
    159 
    160     // Initialize number of referral forms to generate
    161     var nofFormSetsDefault = 50;
    162     if (refVariant == 'kit2_neoadjuvant')
    163     {
    164       nofFormSetsDefault = 25;
    165     }
    166     frm.nofFormSets.value = nofFormSetsDefault;   
    167    
    168     refStartScanbIdPure = jsonRefStartInfo['startScanbIdPure'];
    169     var lastUpdated = jsonRefStartInfo['lastUpdated'];
    170     // Add site prefix to referral pure start SCAN-B id
    171     var refStartScanbId = site + refStartScanbIdPure;
    172     if (lastUpdated != null && lastUpdated != '')
    173     {
    174       Doc.element('scanbIdLastUpdated').innerHTML = lastUpdated;
    175     }
    176     frm.caseName.value = refStartScanbId;
    177 
    178     Doc.show('gonext');
    179 
    180     Doc.show('step-2');
    181   }
    182 
    183   istat.caseNameOnChange = function()
    184   {
    185     var frm = document.forms['reggie'];
    186     var caseName = frm.caseName.value.toUpperCase();
    187     caseIsValid = false;
    188     Doc.addClass('gonext', 'disabled');
    189     if (caseName == '')
    190     {
    191       Wizard.setInputStatus('caseName', 'invalid', 'Missing');
    192       frm.caseName.focus();
    193       return;
    194     }
    195     if (!Reggie.isValidCaseName(caseName, true)) // Allow C/D suffix to be used
    196     {
    197       Wizard.setInputStatus('caseName', 'invalid', 'Only 7-digits name + optional \'C\' or \'D\' is allowed.');
    198       frm.caseName.focus();
    199       return;
    200     }
    201     // Check if pure case name < stored next pure case name
    202     var curRefStartScanbIdPure = caseName.substring(2);
    203     if (curRefStartScanbIdPure < refStartScanbIdPure)
    204     {
    205       var confirmMsg = 'Check to verify use of pure SCAN-B ID < ' + refStartScanbIdPure + ' (stored value).';
    206       Wizard.showGoNextConfirmation(true, confirmMsg);
    207       return;
    208     }
    209 
    210     frm.caseName.value = caseName;
    211     Wizard.setInputStatus('caseName', 'valid');
    212     caseIsValid = true;
    213     Doc.removeClass('gonext', 'disabled');
    214   }
    215 
    216   istat.validateStep2 = function(event)
    217   {
    218     var valid = true;
    219     valid &= Wizard.isValid('caseName');
    220     if (!valid) event.preventDefault();
    221 
    222     istat.generateReferralForms();
    223   }
    224 
    225   istat.generateReferralForms = function()
    226   {
    227     var frm = document.forms['reggie'];
    228     var refVariant = frm.referralvariant.value;
    229     var startCaseName = frm.caseName.value;
    230     var nofFormSets = frm.nofFormSets.value;
    231 
    232     Doc.addClass('caseName', 'disabled');
    233     Doc.addClass('nofFormSets', 'disabled');
    234 
    235     Doc.hide('gonext');
    236 
    237     var url = '../ReferralGenerator.servlet?ID='+App.getSessionId();
    238     url += '&cmd=GenerateReferralForms';
    239     url += '&referralvariant='+encodeURIComponent(refVariant);
    240     url += '&startcasename='+encodeURIComponent(startCaseName);
    241     url += '&nofformsets='+encodeURIComponent(nofFormSets);
    242 
    243     Wizard.showLoadingAnimation('Generating referral forms...', 'ref-gen-progress');
    244     Wizard.asyncJsonRequest(url, istat.initializeStep3);
    245 /*
    246     // POST
    247     Wizard.showLoadingAnimation('Generating referral forms...', 'ref-gen-progress');
    248     Wizard.asyncJsonRequest(url, istat.initializeStep2, 'POST', formData);
    249 */
    250   }
    251 
    252   istat.initializeStep3 = function(response)
    253   {
    254     var frm = document.forms['reggie'];
    255     Wizard.setCurrentStep(3);
    256     Wizard.showFinalMessage(response.messages);
    257 
    258     Doc.hide('gonext');
    259     Doc.show('downloadformbatch1');
    260     Doc.show('downloadformbatch2');
    261     Doc.show('updateusedscanbidlist');
    262  
    263     Doc.show('step-3');
    264   }
    265    
    266   istat.initializeStep3a = function(response)
    267   {
    268     var frm = document.forms['reggie'];
    269     Wizard.setCurrentStep(3);
    270     Wizard.showFinalMessage(response.messages);
    271 
     204      Wizard.asyncJsonRequest(url, xport.submissionResults, 'POST', JSON.stringify(submitInfo));
     205    }
     206  }
     207 
     208  xport.submissionResults = function(response)
     209  {
     210    var msg = response.messages;
     211    msg[msg.length] = '[HTML]BD47 file save to: <span id="downloadBd47" class="link" title="Download">'+response.bd47Path + '</span>';
     212    msg[msg.length] = '[HTML]<span id="viewLogFile2" class="link">View log file</span>';
     213    Wizard.showFinalMessage(msg);
     214    Data.set('viewLogFile2', 'file-id', response.logFile);
     215    Data.set('downloadBd47', 'file-path', response.bd47Path);
     216    Events.addEventHandler('viewLogFile2', 'click', xport.viewLogFile);
     217    Events.addEventHandler('downloadBd47', 'click', xport.downloadBD47File);
    272218    Doc.show('gorestart');
    273     Doc.hide('gonext');
    274     Doc.show('downloadformbatch1');
    275     Doc.show('downloadformbatch2');
    276     Doc.show('updateusedscanbidlist');
    277     Doc.addClass('updateusedscanbidlist', 'disabled');
    278  
    279     Doc.show('step-3');
    280   }
    281    
    282   istat.downloadFormBatch1 = function()
    283   {
    284     istat.downloadFormBatch(1);
    285   }
    286 
    287   istat.downloadFormBatch2 = function()
    288   {
    289     istat.downloadFormBatch(2);
    290   }
    291 
    292   istat.downloadFormBatch = function(batchType)
    293   {
    294     var frm = document.forms['reggie'];
    295     var startCaseName = frm.caseName.value;
    296     var nofFormSets = frm.nofFormSets.value;
    297 
    298     var url = '../ReferralGenerator.servlet?ID='+App.getSessionId();
    299     url += '&cmd=DownloadFormBatchFile';
    300     url += '&batchType='+batchType;
    301     url += '&startcasename='+encodeURIComponent(startCaseName);
    302     url += '&nofformsets='+encodeURIComponent(nofFormSets);
    303     window.open(url);
    304   }
    305 
    306   istat.updateUsedScanbIdList = function()
    307   {
    308     var frm = document.forms['reggie'];
    309     var startCaseName = frm.caseName.value;
    310     var nofFormSets = frm.nofFormSets.value;
    311 
    312     var url = '../ReferralGenerator.servlet?ID='+App.getSessionId();
    313     url += '&cmd=UpdateUsedScanbIdList';
    314     url += '&startcasename='+encodeURIComponent(startCaseName);
    315     url += '&nofformsets='+encodeURIComponent(nofFormSets);
    316 
    317     Wizard.asyncJsonRequest(url, istat.initializeStep3a);
    318   }
    319 
    320   istat.selectOptionsDisabled = function(id, value)
    321   {
    322     var op = document.getElementById(id).getElementsByTagName('option');
    323     for (var i = 0; i < op.length; i++)
    324     {
    325       op[i].disabled = value;
    326     }
    327   }
    328 
    329   return istat;
     219  }
     220
     221 
     222  xport.onPreviewLoaded = function(response)
     223  {   
     224    var allLines = response.csv.split('\n');
     225    var maxLine = allLines.length - 2; // First line is a header line
     226   
     227    var html = '<tr><th>'+allLines[0].replace(/;/g, '</th><th>')+'</th></tr>';
     228    for (var i = 1 ; i <= maxLine; i++)
     229    {
     230      html += '<tr><td>'+allLines[i].replace(/;/g, '</td><td>')+'</td></tr>';
     231    }
     232
     233    previewList.innerHTML = '<table>'+html+'</table>';
     234    Doc.show('previewWrapper');
     235  }
     236
     237   
     238  return xport;
    330239}();
    331240
    332 Doc.onLoad(Istat.initPage);
    333 
     241Doc.onLoad(Xport.initPage);
     242
  • extensions/net.sf.basedb.reggie/trunk/resources/personal/generate-referral-forms.jsp

    r4080 r6277  
    1010  import="net.sf.basedb.clients.web.extensions.ExtensionsControl"
    1111  import="net.sf.basedb.util.Values"
    12   import="net.sf.basedb.util.formatter.DateFormatter"
    1312%>
    1413<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
     
    2524  dc = sc.newDbControl();
    2625  final User user = User.getById(dc, sc.getLoggedInUserId());
    27   DateFormatter dateFormat = new DateFormatter("yyyy-MM-dd");
    2826%>
    2927<base:page type="default" >
    3028<base:head
    3129  scripts="~../reggie-2.js,~generate-referral-forms.js"
    32   styles="path.css,~../css/reggie-2.css"
     30  styles="path.css,~../css/reggie-2.css,~export.css"
    3331>
    34 <style>
    35 #not-found
    36 {
    37   margin: 0 1em 0 4em;
    38   padding: 0.5em 1em;
    39   font-family: monospace,Courier New;
    40   max-height: 25em;
    41   overflow: auto;
    42 }
    43 </style>
    4432</base:head>
    4533<base:body>
     
    4735  <p:path><p:pathelement
    4836    title="Reggie" href="<%="../index.jsp?ID="+ID%>"
    49     /><p:pathelement title="Generate referral forms"
     37    /><p:pathelement title="Referral ID generator"
    5038    /></p:path>
    5139
    5240  <div class="content">
    53   <form name="reggie" id="wizard" class="wizard">
     41    <form name="reggie" id="wizard" class="wizard">
     42   
     43    <div class="step" id="step-1">
     44      <div class="step-no">1</div>
     45      <div class="step-title">Enter info on the referral form batch to create</div>
     46      <div class="step-content">
     47   
     48        <table class="step-form">
     49        <tr>
     50          <td class="prompt">Site</td>
     51          <td class="input">
     52            <select id="site" name="site" style="width: 15em;"></select>
     53          </td>
     54          <td class="status" id="site.status"></td>
     55          <td class="help">
     56            <span id="site.message" class="message"></span>
     57            Select the site to generate referral ID values for.
     58          </td>
     59        </tr>
     60        <tr>
     61          <td class="prompt">Kit type</td>
     62          <td class="input">
     63            <label><input type="radio" name="kitType" id="kitTypeStandard" value="standard" checked>Standard</label><br>
     64            <label><input type="radio" name="kitType" id="kitTypeNeo" value="neoadjuvant">Neo-adjuvant</label>
     65          </td>
     66          <td valign="top" class="status" id="kitType.status"></td>
     67          <td class="help">
     68            <span id="kitType.message" class="message"></span>
     69            Select the type of kit.
     70          </td>
     71        </tr>
     72        <tr>
     73          <td class="prompt">Start number
     74            <span id="sitePrefix" style="float: right; font-weight: normal;">00 -</span>
     75          </td>
     76          <td class="input">
     77            <input type="text" name="startNumber" id="startNumber"
     78            class="required auto-init" data-auto-init="focus-on-enter" data-next-focus="numKits"
     79            style="width: 6em;" maxlength="5">
     80            <span id="viewLogFile" class="link" style="display: none;"
     81              title="Opens in a new window">View log file</span>
     82            </td>
     83          <td class="status" id="startNumber.status"></td>
     84          <td class="help">
     85            <span id="startNumber.message" class="message"></span>
     86            Enter the 5-digit number of the first referral ID. The site prefix
     87            is automatically added to create a 7-digit SCAN-B ID.
     88          </td>
     89        </tr>
     90        <tr>
     91          <td class="prompt">Number of kits</td>
     92          <td class="input"><input type="text" name="numKits" id="numKits"
     93            class="required" style="width: 6em;" maxlength="3"> (max 100)</td>
     94          <td class="status" id="numKits.status"></td>
     95          <td class="help">
     96            <span id="numKits.message" class="message"></span>
     97            Number of referral kits to generate.
     98          </td>
     99        </tr>
     100        </table>
    54101 
    55   <div class="step" id="step-1">
    56     <div class="step-no">1</div>
    57     <div class="step-title">Enter info on the referral form batch to create</div>
    58     <div class="step-content">
     102      </div>
     103    </div>
    59104 
    60       <div class="bg-filled-50" style="padding: 2px;">
    61         * A form set consists of forms with the same base SCAN-B ID, i.e. ignoring optional suffix.<br>
    62         * A form batch consists of a number of form sets with consecutive SCAN-B ID's.<br>
    63         * A form batch is distributed as two files, with forms intended for printing on<br>
    64         &nbsp;&nbsp;&nbsp;referral form sheets or regular paper, respectively:<br>
    65         <br>
    66         &nbsp;&nbsp;&nbsp;Batch file 1: Form sets with 2 or 4 (Kit 2) forms to be printed on referral form sheets.<br>
    67         &nbsp;&nbsp;&nbsp;Batch file 2: Form sets with 2 forms to be printed on regular paper.<br>
    68         <br>
    69         &nbsp;&nbsp;&nbsp;Printing options:<br>
    70         <br>
    71         &nbsp;&nbsp;&nbsp;Batch file 1: One-sided printing, one page per sheet, print size "Actual size".<br>
    72         &nbsp;&nbsp;&nbsp;Batch file 2: Double-sided printing, two pages per sheet, print size "Actual size".<br>
    73         <br>
    74       </div>
    75 
    76       <table class="step-form">
    77       <tr>
    78         <td class="prompt">Site</td>
    79         <td class="input">
    80           <select id="sites" name="sites" style="width: 15em;"></select>
    81         </td>
    82         <td class="status" id="sites.status"></td>
    83         <td class="help">
    84           <span id="sites.message" class="message"></span>
    85           Select what site to generate referral forms for.
    86         </td>
    87       </tr>
    88       <tr>
    89         <td class="prompt">Form set variant</td>
    90         <td class="input">
    91           <select name="referralvariant" id="referralvariant">
    92             <option value="kit1_standard" selected="yes">Kit 1 - Standard</option>
    93             <option value="kit2_neoadjuvant">Kit 2 - Neoadjuvant therapy</option>
    94           </select>
    95         </td>
    96         <td valign="top" class="status" id="referralvariant.status"></td>
    97         <td class="help">
    98           <span id="referralvariant.message" class="message"></span>
    99           Select form set variant.
    100         </td>
    101       </tr>
    102       </table>
    103       <div id="step1message"></div>
    104 
     105    <div id="wizard-status"></div>
     106    <div id="wizard-progress"></div>
     107 
     108    <table class="navigation" id="navigation">
     109    <tr>
     110      <td><base:button id="gorestart" title="Restart" image="<%=home+"/images/goback.png"%>" /></td>
     111      <td><base:button id="gopreview" title="Preview" image="<%=home+"/images/export.png"%>" /></td>
     112      <td><base:button id="goregister" title="Register" image="<%=home+"/images/gonext.png"%>" /></td>
     113      <td id="gonext-message" class="message"></td>
     114    </tr>
     115    </table>
     116   
     117    </form>
     118 
     119    <div id="previewWrapper" style="display: none; top: 13em;">
     120      <div id="previewList"></div>
    105121    </div>
    106   </div>
    107 
    108   <div class="step" id="step-2">
    109     <div class="step-no">2</div>
    110     <div class="step-title">Referral form generation</div>
    111     <div class="step-content">
    112 
    113       <table class="step-form">
    114       <tr>
    115         <td class="prompt">Start SCAN-B ID</td>
    116         <td class="input"><input type="text" name="caseName" id="caseName"
    117           class="required auto-init" data-auto-init="focus"
    118           style="width: 12em;" maxlength="12"></td>
    119         <td class="status" id="caseName.status"></td>
    120         <td class="help">
    121           <span id="caseName.message" class="message"></span>
    122           The 7-digit SCAN-B ID (barcode) for the first referral form set. Last updated: <b><span id="scanbIdLastUpdated"></span></b>.
    123         </td>
    124       </tr>
    125       <tr>
    126         <td class="prompt"># Form sets</td>
    127         <td class="input"><input type="text" name="nofFormSets" id="nofFormSets"
    128           class="required auto-init" data-auto-init="focus"
    129           style="width: 12em;" maxlength="12"></td>
    130         <td class="status" id="nofFormSets.status"></td>
    131         <td class="help">
    132           <span id="nofFormSets.message" class="message"></span>
    133           Number of form sets to generate.
    134         </td>
    135       </tr>
    136       </table>
    137       <div id="step2message"></div>
    138     </div>
    139   </div>
    140 
    141   <div class="step" id="step-3">
    142     <div class="step-no">3</div>
    143     <div class="step-title">Referral form download</div>
    144     <div class="step-content">
    145 
    146       <table class="step-form">
    147       </table>
    148       <div id="step3message"></div>
    149     </div>
    150   </div>
    151 
    152   <div id="wizard-status"></div>
    153   <div id="wizard-progress"></div>
    154 
    155   <div id="not-found" style="display: none;" class="bg-filled-100 fullborder"></div>
    156 
    157   <table class="navigation" id="navigation">
    158   <tr>
    159     <td><base:button id="gocancel" title="Cancel" /></td>
    160     <td><base:button id="gonext" title="Next" image="<%=home+"/images/gonext.png"%>" /></td>
    161     <td><base:button id="gorestart" title="Restart" image="<%=home+"/images/goback.png"%>" /></td>
    162     <td><base:button id="downloadformbatch1" title="Download form batch file 1" image="<%=home+"/images/download.png"%>" /></td>
    163     <td><base:button id="downloadformbatch2" title="Download form batch file 2" image="<%=home+"/images/download.png"%>" /></td>
    164     <td><base:button id="updateusedscanbidlist" title="Update used SCAN-B ID list" image="<%=home+"/images/gonext.png"%>" /></td>
    165     <td id="gonext-message" class="message"></td>
    166   </tr>
    167   </table>
    168122 
    169   </form>
    170123  </div>
    171124 
  • extensions/net.sf.basedb.reggie/trunk/resources/reggie-2.js

    r6127 r6277  
    2121    Verify that the 'case' name is a 7-digit value + optional C/D suffix
    2222  */
    23   reggie.isValidCaseName = function isValidCaseName(caseName, allowSuffix)
     23  reggie.isValidCaseName = function(caseName, allowSuffix)
    2424  {
    2525    return caseName.match(allowSuffix ? CASENAME_WITH_SUFFIX : CASENAME);
    2626  }
     27 
     28  /**
     29    Alternate check of 'case' name that supports checking prefixes
     30    and suffixes. The prefixes and suffixes are inserted into
     31    the regexp as they are so they should typically be a pipe-separated
     32    list of values inside parenthesis: (C|D)?
     33  */
     34  reggie.checkValidCaseName = function(caseName, prefix, suffix)
     35  {
     36    var rexp = new RegExp('^'+(prefix||'')+'\\d{7}'+(suffix||'')+'$');
     37    return rexp.test(caseName);
     38  }
    2739 
    2840  /*
     
    876888    if (verify && !verify.checked) return;
    877889   
     890    // Send 'wizard-validate' event to current step
    878891    var details = { 'auto': auto };
    879    
     892    if (!wizard.validateCurrentStep(details)) return;
     893
     894    // Hide all navigation buttons and disable form controls in current step
     895    internal.hideButtons('navigation');
     896    internal.disableStep('step-'+currentStep);
     897   
     898    // Send 'wizard-initialize' to the next step
     899    var nextStep = Doc.element('step-'+(currentStep+1));
     900    var evt = document.createEvent('CustomEvent');
     901    evt.initCustomEvent('wizard-initialize', true, true, details);
     902    nextStep.dispatchEvent(evt);
     903  }
     904 
     905  wizard.validateCurrentStep = function(details)
     906  {
    880907    // Send 'wizard-validate' event to current step
    881908    var step = Doc.element('step-'+currentStep);
     
    885912    {
    886913      wizard.notifyError();
    887       return;
    888     }
    889 
    890     // Hide all navigation buttons and disable form controls in current step
    891     internal.hideButtons('navigation');
    892     internal.disableStep(step);
    893    
    894     // Send 'wizard-initialize' to the next step
    895     var nextStep = Doc.element('step-'+(currentStep+1));
    896     var evt = document.createEvent('CustomEvent');
    897     evt.initCustomEvent('wizard-initialize', true, true, details);
    898     nextStep.dispatchEvent(evt);
     914      return false;
     915    }
     916    return true;
    899917  }
    900918 
     
    15801598        debug += '<li class="debug">' + Strings.encodeTags(msgLine.replace('[Debug]', ''));
    15811599      }
     1600      else if (msgLine.indexOf('[HTML]') >= 0)
     1601      {
     1602        msg += '<li class="ok">' + msgLine.replace('[HTML]', '');
     1603      }
    15821604      else
    15831605      {
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/Reggie.java

    r6127 r6277  
    179179
    180180  /**
    181     Path to the directory on the BASE file system where referral form templates for
    182     different sites are stored.
    183     @since 4.6
    184   */
    185   public static final String REFERRAL_FORM_TEMPLATES_DIR = "/home/SCANB/ReferralFormTemplatesInUse";
    186 
    187   /**
    188     Path to the directory on the BASE file system where old referral form templates for
    189     different sites are stored.
    190     @since 4.6
    191   */
    192   public static final String REFERRAL_FORM_TEMPLATES_OLD_DIR = "/home/SCANB/ReferralFormTemplatesOld";
    193 
    194   /**
    195181    Path to the directory on the BASE file system where frozen tissue CSV files are expected
    196182    to be stored.
     
    213199  public static final String TEMPLATES_DIR = "/home/SCANB/Templates";
    214200
     201  /**
     202    Path to the directory on the BASE file system where referral ID log files are stored.
     203    @since 4.31.2
     204  */
     205  public static final String REFERRAL_LOGS_DIR = "/home/SCANB/ReferralIdLogs";
     206 
     207   
    215208  /**
    216209    Path to the directory on the BASE file system where files associated with
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/Site.java

    r6110 r6277  
    1111import net.sf.basedb.reggie.dao.ReggieRole;
    1212import net.sf.basedb.reggie.logo.Logo;
     13import net.sf.basedb.util.MD5;
    1314
    1415import org.json.simple.JSONObject;
     
    141142  }
    142143
     144  /**
     145    Convert the numeric SCAN-B number, which should be a value
     146    between 1 and 99,999 to a 7-digit SCAN-B ID with site prefix.
     147    The UNKNOW site will not add a prefix and returns a 5-digit
     148    string instead.
     149    @since 4.31.2
     150  */
     151  public String toScanbID(int scanbNumber)
     152  {
     153    return (prefix==null?"":prefix)+MD5.leftPad(Integer.toString(scanbNumber), '0', 5);
     154  }
     155 
    143156 
    144157  /**
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/dao/Annotationtype.java

    r6215 r6277  
    298298
    299299  /**
     300    The "BD47_ID" annotation, used for samples that end up in
     301    the biobank. This annotation store the ID that the biobank
     302    is using for the sample.
     303    @since 4.31.2
     304   */
     305  public static final Annotationtype BD47_ID =
     306    new Annotationtype("BD47_ID", Type.STRING, false, Item.SAMPLE);
     307
     308 
     309  /**
    300310    The "ReasonIfNoSpecimen" annotation type, used
    301311    for samples (NoSpecimen). It is a string annotation.
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/servlet/BloodRegistrationServlet.java

    r5421 r6277  
    6969       
    7070        // Find blood + case by case name (blood name = case name + '.b' suffix)
    71         String caseName = req.getParameter("caseName");
     71        String originalCaseName = req.getParameter("caseName");
     72        String caseName = stripPrefix(originalCaseName, "K");
    7273        Site site = Site.findByCaseName(caseName);
    7374        json.put("siteInfo", site.asJSONObject());
     
    136137         
    137138        }
     139        jsonBlood.put("originalCaseName", originalCaseName);
    138140        json.put("bloodInfo", jsonBlood);
    139141       
     
    215217        Annotationtype.BLOOD_SAMPLE.setAnnotationValue(dc, blood, bloodSample);
    216218        Annotationtype.OTHER_PATH_NOTE.setAnnotationValue(dc, blood, otherPathNote);
     219        Annotationtype.BD47_ID.setAnnotationValue(dc, blood, jsonBlood.get("originalCaseName"));
    217220
    218221        Number copyConsentId = (Number)jsonBlood.get("copyConsent");
     
    284287   
    285288  }
     289 
     290  private String stripPrefix(String s, String prefix)
     291  {
     292    if (s != null && prefix != null && s.startsWith(prefix))
     293    {
     294      s = s.substring(prefix.length());
     295    }
     296    return s;
     297  }
     298 
    286299 
    287300  private BioSource getOrCreatePatient(DbControl dc, JSONObject jsonPat, JSONArray jsonMessages)
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/servlet/InstallServlet.java

    r6221 r6277  
    251251        }
    252252       
    253         jsonChecks.add(checkClient(dc, ClientApp.REGGIE, effectivePermissionsUse, createIfMissing));
     253        jsonChecks.add(checkClient(dc, ClientApp.REGGIE, effectivePermissionsUse.merge(patientCuratorWrite), createIfMissing));
    254254        jsonChecks.add(checkClient(dc, ClientApp.SCANB_DELIVERY, scanbDeliveryUse, createIfMissing));
    255255        jsonChecks.add(checkClient(dc, ClientApp.WEB_CLIENT, scanbLabUse, createIfMissing));
     
    410410        jsonChecks.add(checkAnnotationType(dc, Annotationtype.BLOOD_SAMPLE, 1, new ValueOptions("PreNeo", "PreOp", "FollowUp06", "FollowUp12", "FollowUp36"), createIfMissing, effectivePermissionsUse));
    411411        jsonChecks.add(checkAnnotationType(dc, Annotationtype.BLOOD_RCCIDNUMBER, 1, null, createIfMissing, effectivePermissionsUse));
     412        jsonChecks.add(checkAnnotationType(dc, Annotationtype.BD47_ID, 1, null, createIfMissing, effectivePermissionsUse));
    412413
    413414        jsonChecks.add(checkAnnotationType(dc, Annotationtype.SAMPLING_DATETIME, 1, null, createIfMissing, effectivePermissionsUse));
     
    830831            Annotationtype.BLOOD_SERUM, Annotationtype.BLOOD_SAMPLE,
    831832            Annotationtype.BLOOD_RCCIDNUMBER, Annotationtype.OTHER_PATH_NOTE,
     833            Annotationtype.BD47_ID,
    832834            Annotationtype.DO_NOT_USE, Annotationtype.DO_NOT_USE_COMMENT));
    833835
     
    11741176        jsonChecks.add(checkDirectory(dc, Reggie.EXTERNAL_ANALYSIS_DIR, createIfMissing, effectivePermissionsUse));
    11751177        jsonChecks.add(checkDirectory(dc, Reggie.DELIVERY_DIR, createIfMissing, patientCuratorUse, scanbDeliveryRead));
    1176         jsonChecks.add(checkDirectory(dc, Reggie.REFERRAL_FORM_TEMPLATES_DIR, createIfMissing, patientCuratorUse));
    1177         jsonChecks.add(checkDirectory(dc, Reggie.REFERRAL_FORM_TEMPLATES_OLD_DIR, createIfMissing, patientCuratorUse));
    11781178        jsonChecks.add(checkDirectory(dc, Reggie.TEMPLATES_DIR, createIfMissing, effectivePermissionsUse));
     1179        jsonChecks.add(checkDirectory(dc, Reggie.REFERRAL_LOGS_DIR, createIfMissing, effectivePermissionsUse));
    11791180        jsonChecks.add(checkDirectory(dc, Reggie.EXTERNAL_LIB_PLATES_DIR, createIfMissing, effectivePermissionsUse));
    1180         // Creates sub-directories with names equals to site prefixes
    1181         for (Site site: Site.getAllSites())
    1182         {
    1183           if (site.getPrefix() != null)
    1184           {
    1185             String siteDirName = Reggie.REFERRAL_FORM_TEMPLATES_DIR + "/" + site.getPrefix();
    1186             jsonChecks.add(checkDirectory(dc, siteDirName, createIfMissing, patientCuratorUse));
    1187             siteDirName = Reggie.REFERRAL_FORM_TEMPLATES_OLD_DIR + "/" + site.getPrefix();
    1188             jsonChecks.add(checkDirectory(dc, siteDirName, createIfMissing, patientCuratorUse));
    1189           }
    1190         }
    11911181       
    11921182        // Plugin definitions and configurations
     
    40274017
    40284018    /**
     4019      Merge the permission options in this instance with
     4020      another instance. The merge creates a new instance
     4021      and doesn't affect either this nor the other instance.
     4022    */
     4023    PermissionOptions merge(PermissionOptions other)
     4024    {
     4025      PermissionOptions merged = new PermissionOptions();
     4026      merged.groupPermissions.putAll(this.groupPermissions);
     4027      merged.projectPermissions.putAll(projectPermissions);
     4028     
     4029      for (Map.Entry<Project, Permission> entry : other.projectPermissions.entrySet())
     4030      {
     4031        Project p = entry.getKey();
     4032        Permission perm = entry.getValue();
     4033        boolean doMerge = true;
     4034        if (merged.projectPermissions.containsKey(p))
     4035        {
     4036          // Should we replace?
     4037          Permission p1 = merged.projectPermissions.get(p);
     4038          if (p1 != null)
     4039          {
     4040            if (perm == null || perm.ordinal() < p1.ordinal()) doMerge = false;
     4041          }
     4042        }
     4043        if (doMerge) merged.projectPermissions.put(p, perm);
     4044      }
     4045     
     4046      for (Map.Entry<Group, Permission> entry : other.groupPermissions.entrySet())
     4047      {
     4048        Group g = entry.getKey();
     4049        Permission perm = entry.getValue();
     4050        boolean doMerge = true;
     4051        if (merged.groupPermissions.containsKey(g))
     4052        {
     4053          // Should we replace?
     4054          Permission p1 = merged.groupPermissions.get(g);
     4055          if (p1 != null)
     4056          {
     4057            if (perm == null || perm.ordinal() < p1.ordinal()) doMerge = false;
     4058          }
     4059        }
     4060        if (doMerge) merged.groupPermissions.put(g, perm);
     4061      }
     4062     
     4063      return merged;
     4064    }
     4065   
     4066    /**
    40294067      Set a permission for the given group.
    40304068    */
  • extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/servlet/ReferralGeneratorServlet.java

    r6070 r6277  
    22
    33import java.io.BufferedReader;
    4 import java.io.FileInputStream;
    5 import java.io.FileOutputStream;
    6 import java.io.FileWriter;
    74import java.io.IOException;
    85import java.io.InputStream;
     
    107import java.io.OutputStream;
    118import java.io.OutputStreamWriter;
    12 import java.text.SimpleDateFormat;
     9import java.io.Writer;
     10import java.nio.charset.StandardCharsets;
    1311import java.util.ArrayList;
     12import java.util.Collections;
    1413import java.util.Date;
    15 import java.util.HashMap;
    1614import java.util.List;
    1715
     
    2422import org.json.simple.JSONObject;
    2523
    26 import com.itextpdf.kernel.pdf.PdfDocument;
    27 import com.itextpdf.kernel.pdf.PdfReader;
    28 
    29 import net.sf.basedb.core.Application;
     24import net.sf.basedb.core.ClientDefaultSetting;
    3025import net.sf.basedb.core.DbControl;
    31 import net.sf.basedb.core.Directory;
    3226import net.sf.basedb.core.File;
    33 import net.sf.basedb.core.ItemQuery;
    3427import net.sf.basedb.core.Path;
    3528import net.sf.basedb.core.SessionControl;
    36 import net.sf.basedb.core.SimpleProgressReporter;
    37 import net.sf.basedb.core.query.Hql;
    38 import net.sf.basedb.core.query.Orders;
    39 import net.sf.basedb.reggie.converter.DateToStringConverter;
    4029import net.sf.basedb.reggie.JsonUtil;
    4130import net.sf.basedb.reggie.Reggie;
     31import net.sf.basedb.reggie.Site;
     32import net.sf.basedb.reggie.dao.ClientApp;
    4233import net.sf.basedb.reggie.dao.ReggieRole;
    43 import net.sf.basedb.reggie.pdf.PdfUtil7;
    44 import net.sf.basedb.reggie.pdf.PdfUtil7.Align;
    45 import net.sf.basedb.reggie.pdf.PdfUtil7.Options;
    46 import net.sf.basedb.reggie.Site;
     34import net.sf.basedb.util.FileUtil;
    4735import net.sf.basedb.util.Values;
    4836import net.sf.basedb.util.error.ThrowableUtil;
     
    5240  extends HttpServlet
    5341{
    54   private static final long serialVersionUID = 2550233926528990677L;
    55   private static final String REF_START_INFO_FILENAME = "scanb_referral_start_info.txt";
    56   private static final String REF_FORM_LOG_FILENAME = "refFormLogFile.txt";
    57   private static final String REF_FORM_BATCH_BASE_FILENAME = "scanb_referral_form_batch";
    58   private static final String REF_VARIANT_KIT_1_STANDARD = "kit1_standard";
    59   private static final String REF_VARIANT_KIT_2_NEOADJUVANT = "kit2_neoadjuvant";
    60   private static final String REFERRAL_GENERATION_PROGRESS_ID = "ref-gen-progress";
    61 
    62   // Remember to add new form template type constants to initializeRefFormTemplNameStartHashMap()
    63   private static final String REF_FORM_TEMPLATE_PATIENT_INFO = "patient-info";
    64   private static final String REF_FORM_TEMPLATE_CLIN_CHEM_BIOPSY = "clinical-chemistry-biopsy";
    65   private static final String REF_FORM_TEMPLATE_CLIN_CHEM_BLOOD = "clinical-chemistry-blood";
    66   private static final String REF_FORM_TEMPLATE_CLIN_CHEM_BLOOD_LUNDCOPY = "clinical-chemistry-blood-lundcopy";
    67   private static final String REF_FORM_TEMPLATE_CLIN_CHEM_BCBLOOD = "clinical-chemistry-bcblood";
    68   private static final String REF_FORM_TEMPLATE_MIDDLE_NEEDLE_BIOPSY = "middle-needle-biopsy";
    69   private static final String REF_FORM_TEMPLATE_CLIN_CHEM = "clinical-chemistry";
    70   private static final String REF_FORM_TEMPLATE_CLIN_PATHOLOGY = "clinical-pathology";
    71   private static final String REF_FORM_TEMPLATE_CONSENT_REPORT = "consent-report";
    72 
    73   // Remember to add new template filename start constants to initializeRefFormTemplNameStartHashMap()
    74   private static final String TEMPLATE_FILENAME_START_PATIENT_INFO = "Patinfo";
    75   private static final String TEMPLATE_FILENAME_START_CLIN_CHEM_BIOPSY = "KlinKemBiopsy-SCAN-B-remiss";
    76   private static final String TEMPLATE_FILENAME_START_CLIN_CHEM_BLOOD = "KlinKem-SCAN-B-blood-biobanken_remiss";
    77   private static final String TEMPLATE_FILENAME_START_CLIN_CHEM_BLOOD_LUNDCOPY = "KlinKem-SCAN-B-blood-biobanken-lundkopia_remiss";
    78   private static final String TEMPLATE_FILENAME_START_CLIN_CHEM_BCBLOOD = "KlinKem-SCAN-B-bcblood-remiss";
    79   private static final String TEMPLATE_FILENAME_START_MIDDLE_NEEDLE_BIOPSY = "PathBiopsy-SCAN-B-remiss";
    80   private static final String TEMPLATE_FILENAME_START_CLIN_CHEM = "Klinkem-SCAN-B-remiss";
    81   private static final String TEMPLATE_FILENAME_START_CLIN_PATHOLOGY = "Path-SCAN-B-remiss";
    82   private static final String TEMPLATE_FILENAME_START_CONSENT_REPORT = "Consent-SCAN-B-remiss";
    83 
    84   private static HashMap<String,String> refFormTemplNameStartHM;
    85 
    86  
    87   private Options boldText = new Options(Align.LEFT).bold().lock(); // LEFT-aligned and bold text
    88  
     42
     43  private static final long serialVersionUID = -5473785391656131849L;
     44
    8945  public ReferralGeneratorServlet()
    9046  {}
    9147
     48  @SuppressWarnings("unused")
    9249  @Override
    9350  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
     
    10158   
    10259    JSONArray jsonMessages = new JSONArray();
    103 
    104     initializeRefFormTemplNameStartHashMap();
    10560
    10661    final SessionControl sc = Reggie.getSessionControl(req);
     
    10964    try
    11065    {
    111       if ("GetReferralStartInfo".equals(cmd))
    112       {
    113         JSONObject jsonRefStartInfo = fetchReferralStartInfo();
    114         json.put("refStartInfo", jsonRefStartInfo);
    115       }
    116       else if ("UpdateUsedScanbIdList".equals(cmd))
    117       {
    118         String startScanbId = req.getParameter("startcasename");
    119         int nofFormSets = Values.getInteger(req.getParameter("nofformsets"), 1);
    120 
    121         String scanbIdPure = startScanbId.substring(2);
    122         String nextScanbIdPure = nextScanbId(scanbIdPure, nofFormSets);
    123 
    124         // Get date string
    125         DateToStringConverter d1 = new DateToStringConverter(new SimpleDateFormat("yyyy-MM-dd"));
    126         String lastUpdated = d1.convert(new Date());
    127 
    128         String refStartInfoFilePath = fetchReferralStartInfoFilePath();
    129         java.io.File file = new java.io.File(refStartInfoFilePath);
    130         FileWriter fileWriter = null;
    131         //
    132         try
    133         {
    134           fileWriter = new FileWriter(file);
    135           String separator = "\t";
    136           fileWriter.write(nextScanbIdPure + separator + lastUpdated + "\n");
    137           //
    138           fileWriter.flush();
    139           fileWriter.close();
    140         }
    141         catch(IOException ex)
    142         {
    143           System.out.println(new Date() + " ReferralGeneratorServlet::doGet(): Could not create filewriter for refStartInfoFilePath = " + refStartInfoFilePath);
    144         }
    145         String message = "Start SCAN-B ID list updated to start at " + nextScanbIdPure;
    146         jsonMessages.add(message);
    147       }
    148       else if ("GetReferralTemplateInfo".equals(cmd))
     66      if ("GetSitesAndStartNumber".equals(cmd))
    14967      {
    15068        dc = sc.newDbControl();
    151 
    152         ReggieRole.checkPermission(dc, "'" + cmd + "' wizard", ReggieRole.PATIENT_CURATOR, ReggieRole.ADMINISTRATOR);
    153 
    154         // Set character encoding to UTF-8 to ensure that Swedish characters will be preserved
    155         req.setCharacterEncoding("UTF-8");
    156         JSONArray jsonMultipleTemplFiles = new JSONArray();
    157 
    158         // Get referral form parameters
    159         String site = Values.getString(req.getParameter("site"), "");
    160         String referralVariant = Values.getString(req.getParameter("referralvariant"), REF_VARIANT_KIT_1_STANDARD);
    161 
    162         //
    163         // Form batch file 1 (Referral forms intended to be printed on referral form sheets)
    164         //
    165         if (referralVariant.equals(REF_VARIANT_KIT_2_NEOADJUVANT))
    166         {
    167           // Biopsy ClinChem Form
    168           jsonMultipleTemplFiles = fetchMultipleTemplateFiles(dc, site, REF_FORM_TEMPLATE_CLIN_CHEM_BIOPSY, jsonMultipleTemplFiles);
    169 
    170           // Middle Needle Biopsy Form
    171           jsonMultipleTemplFiles = fetchMultipleTemplateFiles(dc, site, REF_FORM_TEMPLATE_MIDDLE_NEEDLE_BIOPSY, jsonMultipleTemplFiles);
    172         }
    173 
    174         // ClinChem Form
    175         jsonMultipleTemplFiles = fetchMultipleTemplateFiles(dc, site, REF_FORM_TEMPLATE_CLIN_CHEM, jsonMultipleTemplFiles);
    176 
    177         // Clin Pathology Form
    178         jsonMultipleTemplFiles = fetchMultipleTemplateFiles(dc, site, REF_FORM_TEMPLATE_CLIN_PATHOLOGY, jsonMultipleTemplFiles);
    179          
    180         // BC Blood Form
    181         jsonMultipleTemplFiles = fetchMultipleTemplateFiles(dc, site, REF_FORM_TEMPLATE_CLIN_CHEM_BCBLOOD, jsonMultipleTemplFiles);
    182 
    183         //
    184         // Form batch file 2 (Referral forms intended to be printed on regular paper)
    185         //
    186         // Consent Patient Info  Form
    187         jsonMultipleTemplFiles = fetchMultipleTemplateFiles(dc, site, REF_FORM_TEMPLATE_PATIENT_INFO, jsonMultipleTemplFiles);
    188 
    189         // Consent Report Form
    190         jsonMultipleTemplFiles = fetchMultipleTemplateFiles(dc, site, REF_FORM_TEMPLATE_CONSENT_REPORT, jsonMultipleTemplFiles);
    191          
    192         // Blood Form
    193         jsonMultipleTemplFiles = fetchMultipleTemplateFiles(dc, site, REF_FORM_TEMPLATE_CLIN_CHEM_BLOOD, jsonMultipleTemplFiles);
    194 
    195         // Blood Form (Lund copy)
    196         jsonMultipleTemplFiles = fetchMultipleTemplateFiles(dc, site, REF_FORM_TEMPLATE_CLIN_CHEM_BLOOD_LUNDCOPY, jsonMultipleTemplFiles);
    197 
    198         json.put("multTemplates", jsonMultipleTemplFiles);
    199       }
    200       else if ("GenerateReferralForms".equals(cmd))
    201       {
    202         dc = sc.newDbControl();
    203 
    204         ReggieRole.checkPermission(dc, "'" + cmd + "' wizard", ReggieRole.PATIENT_CURATOR, ReggieRole.ADMINISTRATOR);
    205 
    206         // Set character encoding to UTF-8 to ensure that Swedish characters will be preserved
    207         req.setCharacterEncoding("UTF-8");
    208 
    209         // Get referral form parameters
    210         String referralVariant = Values.getString(req.getParameter("referralvariant"), REF_VARIANT_KIT_1_STANDARD);
    211         String startCaseName = Values.getString(req.getParameter("startcasename"), "");
    212         int nofFormSets = Values.getInteger(req.getParameter("nofformsets"), 1);
    213 //System.out.println(new Date() + " doGet(): cmd = \"" + cmd + "\" startCaseName = " + startCaseName + " nofFormSets = " + nofFormSets);
    214         String scanbIdPrefix = startCaseName.substring(0,2);
    215 
    216         SimpleProgressReporter progress = new SimpleProgressReporter(null);
    217         progressId = REFERRAL_GENERATION_PROGRESS_ID;
    218         sc.setSessionSetting(progressId, progress);
    219         progress.display(0, "Generating referral forms...");
    220         // Set estimated fractions of process time
    221         float progressBatchFile1Fraction = 0.43f;
    222         float progressBatchFile2Fraction = 0.57f;
    223         if (referralVariant.equals(REF_VARIANT_KIT_2_NEOADJUVANT))
    224         {
    225           progressBatchFile1Fraction = 0.56f;
    226           progressBatchFile2Fraction = 0.44f;
    227         }
    228         int progressOffset = 0;
    229         int progressPct = 0;
    230 
    231         // List of used form template filenames for log purposes
    232         List<String> formTemplateFileList = new ArrayList<String>();
    233         // Get new PdfUtil instance
    234         String title = "Title";
    235         String creator = "Creator";
    236         PdfUtil7 pdfUtil = new PdfUtil7(title, creator);
    237         // PdfUtil.open(OutputStream out) must be called before text or images are added (canvas is needed)
    238 
    239         //
    240         // Form batch file 1 (Referral forms intended to be printed on referral form sheets)
    241         //
    242         String pdfOutFilePath = fetchReferralFormBatchFilePath(1);
    243         java.io.File pdfOutFile = new java.io.File(pdfOutFilePath);
    244         OutputStream pdfOutStream = new FileOutputStream(pdfOutFile);
    245         pdfUtil.open(pdfOutStream);
    246         pdfUtil.removePage(1); // We call newPage() later
    247        
    248         String scanbId = startCaseName;
    249 
    250         for (int i = 0; i < nofFormSets; i++)
    251         {
    252           progressPct = Math.round(progressBatchFile1Fraction*100*i/nofFormSets);
    253           progress.display(progressPct, "Generating referral forms...");
    254           if (i > 0)
    255           {
    256             scanbId = nextScanbId(scanbId);
    257           }
    258           String scanbIdBiopsy = scanbId + "C";
    259 
    260           if (referralVariant.equals(REF_VARIANT_KIT_2_NEOADJUVANT))
    261           {
    262             // Biopsy ClinChem Form
    263             pdfUtil = createBiopsyClinChemForm(dc, pdfUtil, scanbIdBiopsy, formTemplateFileList);
    264 
    265             // Middle Needle Biopsy Form
    266             pdfUtil = createMiddleNeedleBiopsyForm(dc, pdfUtil, scanbIdBiopsy, formTemplateFileList);           
    267           }
    268 
    269           // ClinChem Form
    270           pdfUtil = createClinChemForm(dc, pdfUtil, scanbId, formTemplateFileList);
    271 
    272           // Clin Pathology Form
    273           pdfUtil = createClinPathologyForm(dc, pdfUtil, scanbId, formTemplateFileList);
    274          
    275           // BC Blood Form
    276           pdfUtil = createClinChemBcBloodForm(dc, pdfUtil, scanbId, formTemplateFileList);
    277         }
    278         pdfUtil.close();
    279 //System.out.println(new Date() + " doGet(): cmd = \"" + cmd + "\" PDF output file = " + pdfOutFilePath + " created");
    280 
    281         //
    282         // Form batch file 2 (Referral forms intended to be printed on regular paper)
    283         //
    284         pdfUtil = new PdfUtil7(title, creator);
    285         pdfOutFilePath = fetchReferralFormBatchFilePath(2);
    286         pdfOutFile = new java.io.File(pdfOutFilePath);
    287         pdfOutStream = new FileOutputStream(pdfOutFile);
    288         pdfUtil.open(pdfOutStream);
    289         pdfUtil.removePage(1);
    290         scanbId = startCaseName;
    291 
    292         progressOffset += progressPct;
    293         for (int i = 0; i < nofFormSets; i++)
    294         {
    295           progressPct = progressOffset + Math.round(progressBatchFile2Fraction*100*i/nofFormSets);
    296           if (progressPct > 100)
    297           {
    298             progressPct = 100;
    299           }
    300           progress.display(progressPct, "Generating referral forms...");
    301           if (i > 0)
    302           {
    303             scanbId = nextScanbId(scanbId);
    304           }
    305           String scanbIdBiopsy = scanbId + "C";
    306 
    307           // Consent Patient Info  Form
    308           pdfUtil = createPatientInfoForm(dc, pdfUtil, scanbId, formTemplateFileList);
    309 
    310           // Consent Report Form
    311           pdfUtil = createConsentReportForm(dc, pdfUtil, scanbId, formTemplateFileList);
    312          
    313           // Blood Form
    314           pdfUtil = createClinChemBloodForm(dc, pdfUtil, scanbId, formTemplateFileList);
    315          
    316           // Blood Form (Lund copy)
    317           pdfUtil = createClinChemBloodLundCopyForm(dc, pdfUtil, scanbId, formTemplateFileList);
    318         }
    319         pdfUtil.close();
    320 //System.out.println(new Date() + " doGet(): cmd = \"" + cmd + "\" PDF output file = " + pdfOutFilePath + " created");
    321 
    322         progress.display(100, "");
    323         updateReferralFormLogFile(dc, referralVariant, startCaseName, nofFormSets, formTemplateFileList);
    324         dc.commit();
    325         String message = "Referral forms created for SCAN-B ID " + startCaseName + "-" + scanbId;
    326         jsonMessages.add(message);
    327       }
    328       else if ("DownloadFormBatchFile".equals(cmd))
    329       {
    330         // No JSON output
    331         json = null;
    332        
    333         int batchType = Values.getInteger(req.getParameter("batchType"), 1);
    334         String startScanbId = req.getParameter("startcasename");
    335         int nofFormSets = Values.getInteger(req.getParameter("nofformsets"), 1);
    336         String endScanbId = nextScanbId(startScanbId, (nofFormSets-1));
    337         String pdfOutFilePath = fetchReferralFormBatchFilePath(batchType);
    338         String filename = fetchReferralFormBatchFileName(batchType, startScanbId, endScanbId);
    339         // Add time stamp to download filename
    340         DateToStringConverter d2 = new DateToStringConverter(new SimpleDateFormat("yyyyMMdd_HHmm"));
    341         String timeStampStr = d2.convert(new Date());
    342         String fileExt = "";
    343         int fileExtIndex = filename.lastIndexOf(".");
    344         if (fileExtIndex >= 0)
    345         {
    346           // Get file extension
    347           fileExt = filename.substring(fileExtIndex);
    348           // Remove file extension
    349           filename = filename.substring(0, fileExtIndex);
    350         }
    351         filename += "_" + timeStampStr + fileExt;
    352        
    353         resp.setHeader("Content-Disposition", "attachment; filename=" + filename);
    354         //resp.setContentType("text/plain");
    355         resp.setContentType("application/pdf");
    356         resp.setCharacterEncoding("UTF-8");
    357 
    358         // Copy contents from form set PDF file to download buffer
    359         java.io.File file = null;
    360         try
    361         {
    362           file = new java.io.File(pdfOutFilePath);
    363         }
    364         catch (NullPointerException ex)
    365         {
    366           System.out.println(new Date() + " ReferralGeneratorServlet::doGet(): cmd = \"" + cmd + "\" NullPointerException when trying to get file for  = \"" + pdfOutFilePath + "\" e: " + ex);
    367           return;
    368         }
    369         try
    370         {
    371           InputStream in = new FileInputStream(file);
    372           // For binary data, get OutputStream from HttpServletResponse instead of PrintWriter
    373           OutputStream out = resp.getOutputStream();
    374 
    375           // Buffer for portion of data from connection
    376           byte[] buffer = new byte[4096];
    377           int n = -1;
    378           while ((n = in.read(buffer)) != -1)
    379           {
    380             // Write n bytes from the byte array buffer (with offset 0) to the output stream
    381             out.write(buffer, 0, n);
    382           }
    383           out.flush();
    384           out.close();
    385           in.close();
    386         }
    387         catch (Exception e)
    388         {
    389           System.out.println(new Date() + " ReferralGeneratorServlet::doGet(): cmd = \"" + cmd + "\" Exception when trying to copy file \"" + pdfOutFilePath + "\" to \"" + filename + "\". e: " + e);
    390         }
    391       }
     69       
     70        List<Site> sites = new ArrayList<>(Site.getAllSites());
     71        Collections.sort(sites, Site.SORT_BY_NAME);
     72        JSONArray jsonSites = new JSONArray();
     73        for (Site s : sites)
     74        {
     75          JSONObject jsonSite = new JSONObject(s.asJSONObject());
     76          jsonSites.add(jsonSite);
     77        }
     78        json.put("sites", jsonSites);
     79       
     80        ClientDefaultSetting lastReferralID = ClientApp.REGGIE.getSetting(dc, "last-referral-id", false);
     81        if (lastReferralID != null) json.put("lastReferralID", lastReferralID.getValue());
     82
     83        ClientDefaultSetting lastReferralNumKits = ClientApp.REGGIE.getSetting(dc, "last-referral-num-kits", false);
     84        if (lastReferralNumKits != null) json.put("lastNumKits", lastReferralNumKits.getValue());
     85       
     86        // Check if log file exists
     87        Path logPath = new Path(Reggie.REFERRAL_LOGS_DIR+"/referral-id-generator.log", Path.Type.FILE);
     88        File log = File.getByPath(dc, logPath, true);
     89        if (log.isInDatabase())
     90        {
     91          json.put("logFile", log.getId());
     92        }
     93      }
     94
    39295    }
    39396    catch (Throwable t)
     
    401104        json.put("stacktrace", ThrowableUtil.stackTraceToString(t));
    402105      }
     106      else
     107      {
     108        resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, t.getClass().getName() + ": " + t.getMessage());
     109      }
    403110    }
    404111    finally
     
    414121  }
    415122
    416   private void initializeRefFormTemplNameStartHashMap()
    417   {
    418     refFormTemplNameStartHM = new HashMap<>();
    419     refFormTemplNameStartHM.put(REF_FORM_TEMPLATE_PATIENT_INFO, TEMPLATE_FILENAME_START_PATIENT_INFO);
    420     refFormTemplNameStartHM.put(REF_FORM_TEMPLATE_CLIN_CHEM_BIOPSY, TEMPLATE_FILENAME_START_CLIN_CHEM_BIOPSY);
    421     refFormTemplNameStartHM.put(REF_FORM_TEMPLATE_CLIN_CHEM_BLOOD, TEMPLATE_FILENAME_START_CLIN_CHEM_BLOOD);
    422     refFormTemplNameStartHM.put(REF_FORM_TEMPLATE_CLIN_CHEM_BLOOD_LUNDCOPY, TEMPLATE_FILENAME_START_CLIN_CHEM_BLOOD_LUNDCOPY);
    423     refFormTemplNameStartHM.put(REF_FORM_TEMPLATE_CLIN_CHEM_BCBLOOD, TEMPLATE_FILENAME_START_CLIN_CHEM_BCBLOOD);
    424     refFormTemplNameStartHM.put(REF_FORM_TEMPLATE_MIDDLE_NEEDLE_BIOPSY, TEMPLATE_FILENAME_START_MIDDLE_NEEDLE_BIOPSY);
    425     refFormTemplNameStartHM.put(REF_FORM_TEMPLATE_CLIN_CHEM, TEMPLATE_FILENAME_START_CLIN_CHEM);
    426     refFormTemplNameStartHM.put(REF_FORM_TEMPLATE_CLIN_PATHOLOGY, TEMPLATE_FILENAME_START_CLIN_PATHOLOGY);
    427     refFormTemplNameStartHM.put(REF_FORM_TEMPLATE_CONSENT_REPORT, TEMPLATE_FILENAME_START_CONSENT_REPORT);
    428   }
    429 
    430   /**
    431    * Returns path to be used for referral start info file.
    432    *
    433    * @return String Path to be used for report file.
    434    */
    435   private String fetchReferralStartInfoFilePath()
    436   {
    437     String refStartInfoFilePath = null;
    438     String refStartInfoFileName = REF_START_INFO_FILENAME;
    439     if (refStartInfoFileName != null)
    440     {
    441       // Place referral start info file in BASE user files directory
    442       java.io.File userFilesDir = Application.getUserFilesDirectory();
    443       String fileDir = userFilesDir.getAbsolutePath();
    444       refStartInfoFilePath = fileDir + "/" + refStartInfoFileName;
    445     }
    446     return refStartInfoFilePath;
    447   }
    448 
    449   private JSONObject fetchReferralStartInfo()
    450     throws IOException
    451   {
    452     String refStartInfoFilePath = fetchReferralStartInfoFilePath();
    453 
    454     // Copy contents from referral start info file to JSON object
    455     JSONObject jsonRefStartInfo = new JSONObject();
    456     java.io.File file = null;
    457     file = new java.io.File(refStartInfoFilePath);
    458     if (!file.exists())
    459     {
    460       createReferralStartInfoFile();
    461     }
    462     java.io.FileReader fileReader = null;
    463     try
    464     {
    465       fileReader = new java.io.FileReader(file);
    466     }
    467     catch (IOException ex)
    468     {
    469       System.out.println(new Date() + " ReferralGeneratorServlet::fetchReferralStartInfo(): IOException when trying to get file reader for  = \"" + refStartInfoFilePath + "\" e: " + ex);
    470     }
    471     java.io.BufferedReader bufferedReader = new java.io.BufferedReader(fileReader);
    472     StringBuffer stringBuffer = new StringBuffer();
    473     String line;
    474     // Get data from single line, or last, if more than one line
    475     while ((line = bufferedReader.readLine()) != null)
    476     {
    477       String[] columns = line.split("\t", -1);
    478       if (columns != null && columns.length > 0)
    479       {
    480         // Get next SCAN-B id to use without site prefix
    481         String startScanbIdPure = columns[0];
    482         String lastUpdated = "";
    483         if (columns.length > 1)
    484         {
    485           // Get date the next SCAN-B id info was last updated
    486           lastUpdated = columns[1];
    487         }
    488         jsonRefStartInfo.put("startScanbIdPure", startScanbIdPure);
    489         jsonRefStartInfo.put("lastUpdated", lastUpdated);
    490       }
    491     }
    492     fileReader.close();
    493     return jsonRefStartInfo;
    494   }
    495 
    496   private void createReferralStartInfoFile()
    497     throws IOException
    498   {
    499     // Set next pure SCAN-B ID to use to 16000
    500     String nextScanbIdPure = "16000";
    501 
    502     // Get date string
    503     DateToStringConverter d1 = new DateToStringConverter(new SimpleDateFormat("yyyy-MM-dd"));
    504     String lastUpdated = d1.convert(new Date());
    505 
    506     String refStartInfoFilePath = fetchReferralStartInfoFilePath();
    507     java.io.File file = new java.io.File(refStartInfoFilePath);
    508     FileWriter fileWriter = null;
    509     //
    510     try
    511     {
    512       fileWriter = new FileWriter(file);
    513       String separator = "\t";
    514       fileWriter.write(nextScanbIdPure + separator + lastUpdated + "\n");
    515       //
    516       fileWriter.flush();
    517       fileWriter.close();
    518     }
    519     catch(IOException ex)
    520     {
    521       System.out.println(new Date() + " ReferralGeneratorServlet::createReferralStartInfoFile(): Could not create filewriter for refStartInfoFilePath = " + refStartInfoFilePath);
    522     }
    523   }
    524 
    525   /**
    526    * Returns path to be used for referral form batch file.
    527    *
    528    * @param batchType int The type number of the form batch.
    529    * @return String Path to be used for referral form batch file.
    530    */
    531   private String fetchReferralFormBatchFilePath(int batchType)
    532   {
    533     String refFormBatchFilePath = null;
    534     String refFormBatchFileName = fetchReferralFormBatchFileName(batchType);
    535     if (refFormBatchFileName != null)
    536     {
    537       // Place referral form batch file in BASE user files directory
    538       java.io.File userFilesDir = Application.getUserFilesDirectory();
    539       String fileDir = userFilesDir.getAbsolutePath();
    540       refFormBatchFilePath = fileDir + "/" + refFormBatchFileName;
    541     }
    542     return refFormBatchFilePath;
    543   }
    544 
    545   /**
    546    * Returns name to be used for referral form batch file.
    547    *
    548    * @param batchType int The type number of the form batch.
    549    * @return String name to be used for report file.
    550    */
    551   private String fetchReferralFormBatchFileName(int batchType)
    552   {
    553     String refFormBatchFileName = fetchReferralFormBatchFileName(batchType, null, null);
    554     return refFormBatchFileName;
    555   }
    556 
    557   /**
    558    * Returns name to be used for referral form batch file.
    559    *
    560    * @param batchType int The type number of the form batch.
    561    * @param startScanbId String The first SCAN-B ID number in the form batch.
    562    * @param endScanbId String The last SCAN-B ID number in the form batch.
    563    * @return String name to be used for report file.
    564    */
    565   private String fetchReferralFormBatchFileName(int batchType, String startScanbId, String endScanbId)
    566   {
    567     String scanbIdSpec = "";
    568     if (startScanbId != null && !startScanbId.equals(""))
    569     {
    570       scanbIdSpec = "_" + startScanbId;
    571       if (endScanbId != null && !endScanbId.equals(""))
    572       {
    573         scanbIdSpec += "-" + endScanbId;
    574       }
    575     }
    576     String refFormBatchFileName = REF_FORM_BATCH_BASE_FILENAME + "_" + batchType + scanbIdSpec + ".pdf";
    577     return refFormBatchFileName;
    578   }
    579 
    580   /**
    581    * Returns start of referral form template filename.
    582    *
    583    * @param formTemplateName String The String key of the form template file.
    584    * @return String Start of the referral form template filename.
    585    */
    586   private String fetchReferralFormTemplateFilenameStart(String formTemplateName)
    587   {
    588     String refFormTemplateFilename = refFormTemplNameStartHM.get(formTemplateName);
    589     return refFormTemplateFilename;
    590   }
    591 
    592   /**
    593    * Returns JSONArray with list of multiple BASE file items for given referral type.
    594    *
    595    * @param dc DbControl The DbControl to use.
    596    * @param scanbIdPrefix String The SCAN-B ID prefix to create referral form for.
    597    * @param formTemplateName String Name of the form template.
    598    * @param jsonMultipleTemplFiles JSONArray JSONArray with list of multiple template files to add to.
    599    * @return JSONArray JSONArray with list of multiple BASE file items for given referral type.
    600    */
    601   private JSONArray fetchMultipleTemplateFiles(DbControl dc, String scanbIdPrefix, String formTemplateName, JSONArray jsonMultipleTemplFiles)
    602   {
    603     // Get dummy SCAN-B ID
    604     String scanbId = scanbIdPrefix + "00000";
    605     // Get PDF templates for template type
    606     List<File> pdfFiles = fetchReferralFormTemplateFileList(dc, scanbId, formTemplateName);
    607     if (pdfFiles.size() > 1)
    608     {
    609       for (File pdfFile: pdfFiles)
    610       {
    611         JSONObject jsonMultipleTemplFile = new JSONObject();
    612         jsonMultipleTemplFile.put("type", formTemplateName);
    613         jsonMultipleTemplFile.put("file", pdfFile.getName());
    614         jsonMultipleTemplFiles.add(jsonMultipleTemplFile);
    615       }
    616     }
    617     return jsonMultipleTemplFiles;
    618   }
    619 
    620   /**
    621    * Returns list of BASE file items for referral form template file.
    622    *
    623    * @param dc DbControl The DbControl to use.
    624    * @param scanbId String The SCAN-B ID to create referral form for.
    625    * @param formTemplateName String Name of the form template.
    626    * @return List<File> List of BASE file items for referral form template file.
    627    */
    628   private List<File> fetchReferralFormTemplateFileList(DbControl dc, String scanbId, String formTemplateName)
    629   {   
    630     // Get PDF template
    631     String refFormTemplTopDirPath = Reggie.REFERRAL_FORM_TEMPLATES_DIR;
    632     String scanbIdPrefix = scanbId.substring(0,2);
    633     String refFormTemplDirPath = refFormTemplTopDirPath + "/" + scanbIdPrefix;
    634     String refFormTemplFilenameStart = fetchReferralFormTemplateFilenameStart(formTemplateName);
    635     Directory refFormTemplDir = Directory.getNew(dc, new Path(refFormTemplDirPath, Path.Type.DIRECTORY));
    636     ItemQuery<File> fileQuery = refFormTemplDir.getFiles();
    637     fileQuery.order(Orders.asc(Hql.property("name")));
    638     List<File> fileList = fileQuery.list(dc);
    639     List<File> pdfFiles = new ArrayList<File>();
    640     String upperCaseAnglifiedSiteName = fetchUpperCaseAnglifiedSiteName(scanbIdPrefix);
    641     for (int i = 0; i < fileList.size(); i++)
    642     {
    643       File file = fileList.get(i);
    644       if (file.getName().startsWith(refFormTemplFilenameStart))
    645       {
    646         pdfFiles.add(file);
    647       }
    648       else if (file.getName().startsWith(upperCaseAnglifiedSiteName + "-" + refFormTemplFilenameStart))
    649       {
    650         pdfFiles.add(file);
    651       }
    652       else if (file.getName().startsWith(upperCaseAnglifiedSiteName + "_" + refFormTemplFilenameStart))
    653       {
    654         pdfFiles.add(file);
    655       }
    656     }
    657     return pdfFiles;
    658   }
    659 
    660   private String fetchUpperCaseAnglifiedSiteName(String prefix)
    661   {
    662     JSONArray jsonSites = ReportTableUtil.getJSONSites(Site.SORT_BY_NAME);
    663     JSONObject jsonSite = null;
    664     for (int i = 0; i < jsonSites.size(); i++)
    665     {
    666       JSONObject theJsonSite = (JSONObject)jsonSites.get(i);
    667       String sitePrefix = (String)theJsonSite.get("prefix");
    668       if (sitePrefix.equals(prefix))
    669       {
    670         jsonSite = theJsonSite;
    671         break;
    672       }
    673     }
    674     String upperCaseSiteName = null;
    675     if (jsonSite != null)
    676     {
    677       String siteName = (String)jsonSite.get("name");
    678       String anglifiedSiteName = anglifyString(siteName);
    679       upperCaseSiteName = anglifiedSiteName.toUpperCase();
    680     }
    681     return upperCaseSiteName;
    682   }
    683  
    684   /**
    685    * Replaces national Swedish characters "Å,Ä,Ö,å,ä,ö" with
    686    * the root characters "A,A,O,a,a,o", respectively.
    687    *
    688    * @param text String The Swedish text that should be modified to only use English characters.
    689    * @return Sting The input Swedish text modified to only use English characters.
    690    */
    691   private String anglifyString(String text)
    692   {
    693     if (text == null)
    694     {
    695       return null;
    696     }
    697     String anglifiedString = "";
    698     for (int i = 0; i < text.length(); i++)
    699     {
    700       String chr = text.substring(i,i+1);
    701       if (chr.equals("Å"))
    702       {
    703         chr = "A";
    704       }
    705       else if (chr.equals("Ä"))
    706       {
    707         chr = "A";
    708       }
    709       else if (chr.equals("Ö"))
    710       {
    711         chr = "O";
    712       }
    713       if (chr.equals("å"))
    714       {
    715         chr = "a";
    716       }
    717       else if (chr.equals("ä"))
    718       {
    719         chr = "a";
    720       }
    721       else if (chr.equals("ö"))
    722       {
    723         chr = "o";
    724       }
    725       anglifiedString += chr;
    726     }
    727     return anglifiedString;
    728   }
    729 
    730   /**
    731    * Update BASE file item for referral form log file.
    732    *
    733    * @param dc DbControl The DbControl to use.
    734    * @param referralVariant String The referral variant to be created.
    735    * @param startScanbId String The first SCAN-B id in the created form set batch.
    736    * @param nofFormSets int The number of referral form sets created.
    737    * @param formTemplateFileList List<String> List of used form template files.
    738    */
    739   private void updateReferralFormLogFile(DbControl dc, String referralVariant, String startScanbId, int nofFormSets, List<String> formTemplateFileList)
    740   {   
    741     DateToStringConverter d3 = new DateToStringConverter(new SimpleDateFormat("yyyy-MM-dd HH:mm"));
    742     String timeStampStr = d3.convert(new Date());
    743     String endScanbId = nextScanbId(startScanbId, (nofFormSets-1));
    744     // Get comma-separated list of used form template filenames
    745     String formTemplateFiles = "";
    746     for (int i = 0; i < formTemplateFileList.size(); i++)
    747     {
    748       String formTemplateFilename = formTemplateFileList.get(i);
    749       if (i > 0)
    750       {
    751         formTemplateFiles += ",";
    752       }
    753       formTemplateFiles += formTemplateFilename;
    754     }
    755     // Get referral form log file
    756     File logFile = fetchReferralFormLogFile(dc);
    757     try
    758     {
    759       // Read and store current file contents
    760       List<String> lines = new ArrayList<String>();
    761       InputStream in = logFile.getDownloadStream(0);
    762       InputStreamReader ipsr = new InputStreamReader(in, "UTF-8");
    763       BufferedReader br = new BufferedReader(ipsr);
    764       // Read data lines
    765       String rawLine;
    766       while ((rawLine = br.readLine()) != null)
    767       {
    768         lines.add(rawLine);
    769       }
    770       br.close();
    771       ipsr.close();
    772       in.close();
    773       //
    774       OutputStream out = logFile.getUploadStream(false);
    775       OutputStreamWriter writer = new OutputStreamWriter(out);
    776       // Write back old contents
    777       for (int i = 0; i < lines.size(); i++)
    778       {
    779         String line = lines.get(i);
    780         writer.write(line + "\n");
    781       }
    782       // Add new content
    783       String separator = "\t";
    784       String scanbIdRange = startScanbId + "-" + endScanbId;
    785       String line = timeStampStr + separator + referralVariant + separator + scanbIdRange + separator + formTemplateFiles;
    786       writer.write(line + "\n");
    787       //
    788       writer.close();
    789       out.close();
    790     }
    791     catch(Exception e)
    792     {
    793       System.out.println(new Date() + " updateReferralFormLogFile(): Exception e: " + e);
    794     }
    795   }
    796 
    797   /**
    798    * Returns BASE file item for referral form log file.
    799    *
    800    * @param dc DbControl The DbControl to use.
    801    * @return File BASE file item for referral form log file.
    802    */
    803   private File fetchReferralFormLogFile(DbControl dc)
    804   {
    805     // Place referral form log file in form templates directory in BASE file system
    806     Directory refFormLogFileDir = Directory.getNew(dc, new Path(Reggie.REFERRAL_FORM_TEMPLATES_DIR, Path.Type.DIRECTORY));
    807     File logFile = File.getFile(dc, refFormLogFileDir, REF_FORM_LOG_FILENAME, true);
    808     if (!logFile.isInDatabase())
    809     {
    810       dc.saveItem(logFile);
    811     }
    812     return logFile;
    813   }
    814 
    815   private String nextScanbId(String scanbId)
    816   {
    817     String nextScanbId = nextScanbId(scanbId, 1);
    818     return nextScanbId;
    819   }
    820 
    821   /**
    822    * Increments an input SCAN-B id with or without site prefix
    823    * a given increment.
    824    *
    825    * @param scanbId String The SCAN-B id with or without site prefix.
    826    * @param incr Integer Increment of SCAN-B id.
    827    * @return String The SCAN-B id with given increment.
    828    */
    829   private String nextScanbId(String scanbId, Integer incr)
    830   {
    831     String nextScanbId = null;
    832     String scanbPrefix = "";
    833     String scanbIdPure = "";
    834     if (scanbId != null)
    835     {
    836       if (scanbId.length() > 6)
    837       {       
    838         scanbPrefix = scanbId.substring(0,2);
    839         scanbIdPure = scanbId.substring(2);
    840       }
    841       else if (scanbId.length() > 4)
    842       {       
    843         scanbIdPure = scanbId;
    844       }
    845       String scanbIdSuffix = "";
    846       if (scanbIdPure.length() > 5)
    847       {
    848         // Extract SCAN-B ID suffix
    849         scanbIdSuffix = scanbIdPure.substring(scanbIdPure.length() - 1, scanbIdPure.length());
    850         scanbIdPure = scanbIdPure.substring(0, scanbIdPure.length() - 1);
    851       }
    852       // Remove initial zeroes
    853       while (scanbIdPure.indexOf("0") == 0)
    854       {
    855         // Remove initial zero
    856         scanbIdPure = scanbIdPure.substring(1);       
    857       }
    858       String nextScanbIdPure = "";
    859       if (scanbIdPure.length() > 0)
    860       {
    861         int scanbIdPureInt = Integer.parseInt(scanbIdPure);
    862         int nextScanbIdPureInt = scanbIdPureInt + incr;
    863         nextScanbIdPure = "" + nextScanbIdPureInt;
    864       }
    865       // Add initial zeroes
    866       while (nextScanbIdPure.length() < 5)
    867       {
    868         // Add initial zero
    869         nextScanbIdPure = "0" + nextScanbIdPure;       
    870       }
    871       // Add SCAN-B ID prefix and optional suffix
    872       nextScanbId = scanbPrefix + nextScanbIdPure + scanbIdSuffix;
    873     }
    874     return nextScanbId;
    875   }
    876 
    877   private PdfUtil7 createPatientInfoForm(DbControl dc, PdfUtil7 pdfUtil, String scanbId, List<String> formTemplateFileList)
    878     throws IOException
    879   {   
    880     // Get PDF templates of same type
    881     List<File> pdfFiles = fetchReferralFormTemplateFileList(dc, scanbId, REF_FORM_TEMPLATE_PATIENT_INFO);
    882     for (File pdfFile: pdfFiles)
    883     {
    884       pdfUtil = createPatientInfoForm(dc, pdfUtil, pdfFile, scanbId, formTemplateFileList);
    885     }
    886 
    887     return pdfUtil;
    888   }
    889 
    890   private PdfUtil7 createPatientInfoForm(DbControl dc, PdfUtil7 pdfUtil, File pdfFile, String scanbId, List<String> formTemplateFileList)
    891     throws IOException
    892   {   
    893     if (pdfFile == null)
    894     {
    895       return pdfUtil;
    896     }
    897     if (!formTemplateFileList.contains(pdfFile.getName()))
    898     {
    899       formTemplateFileList.add(pdfFile.getName());
    900     }
    901     InputStream pdfInStream = pdfFile.getDownloadStream(0);
    902    
    903     PdfReader reader = new PdfReader(pdfInStream);
    904     PdfDocument template = new PdfDocument(reader);
    905     int numPages = template.getNumberOfPages();
    906     String scanbPrefix = scanbId.substring(0,2);
    907     String scanbResidue = scanbId.substring(2);
    908     String text = scanbPrefix + "-" + scanbResidue;
    909 
    910     for (int pageNo = 1; pageNo <= numPages; pageNo++)
    911     {
    912       pdfUtil.newPage();
    913       pdfUtil.importPdf(template, pageNo, 0, 0, Float.NaN, Float.NaN, Align.LEFT);
    914       pdfUtil.addText(text, 10, 481, 769.2f);
    915     }
    916 
    917     // Add blank extra page, if the number of pages is odd
    918     if (numPages % 2 > 0)
    919     {
    920       pdfUtil.newPage();
    921     }
    922 
    923     return pdfUtil;
    924   }
    925 
    926   private PdfUtil7 createConsentReportForm(DbControl dc, PdfUtil7 pdfUtil, String scanbId, List<String> formTemplateFileList)
    927     throws IOException
    928   {   
    929     // Get PDF templates of same type
    930     List<File> pdfFiles = fetchReferralFormTemplateFileList(dc, scanbId, REF_FORM_TEMPLATE_CONSENT_REPORT);
    931     for (File pdfFile: pdfFiles)
    932     {
    933       pdfUtil = createConsentReportForm(dc, pdfUtil, pdfFile, scanbId, formTemplateFileList);
    934     }
    935 
    936     return pdfUtil;
    937   }
    938 
    939   private PdfUtil7 createConsentReportForm(DbControl dc, PdfUtil7 pdfUtil, File pdfFile, String scanbId, List<String> formTemplateFileList)
    940     throws IOException
    941   {   
    942     if (pdfFile == null)
    943     {
    944       return pdfUtil;
    945     }
    946     if (!formTemplateFileList.contains(pdfFile.getName()))
    947     {
    948       formTemplateFileList.add(pdfFile.getName());
    949     }
    950     InputStream pdfInStream = pdfFile.getDownloadStream(0);
    951     pdfUtil.newPage();
    952     // Import PDF document template
    953     float xOrig = 29.6f;
    954     float yOrig = 17.4f;
    955     int pageNo = 1;
    956     pdfUtil.importPdf(pdfInStream, pageNo, xOrig, yOrig, Float.NaN, Float.NaN, Align.LEFT);
    957     // SCAN-B ID below bar code in upper right section
    958     String text = "SCAN-B " + scanbId;
    959     float textFontSize = 12.1f;
    960     float xTextUpperRight = 430.8f;
    961     float yTextUpperRight = 698.2f;
    962    
    963     pdfUtil.addText(text, textFontSize, xTextUpperRight, yTextUpperRight, boldText);
    964     // SCAN-B ID in lower section
    965     text = scanbId;
    966     textFontSize = 10.7f;
    967     float xTextLowerLeft = 186.0f;
    968     float yTextLowerLeft = 153.4f;
    969     pdfUtil.addText(text, textFontSize, xTextLowerLeft, yTextLowerLeft, boldText);
    970     //
    971     //pdfUtil.drawGrid();
    972 
    973     // Barcode at upper right
    974     float xBarcodeUpperRight = xTextUpperRight + 0.7f;
    975     float yBarcodeUpperRight = yTextUpperRight + 12.0f;
    976     float width = 94.0f;
    977     float height = 20.0f;
    978     pdfUtil.addBarcode(scanbId, xBarcodeUpperRight, yBarcodeUpperRight, width, height, 0);
    979 
    980     // Barcode at upper left
    981     float xBarcodeUpperLeft = 65.0f;
    982     float yBarcodeUpperLeft = yBarcodeUpperRight - 4.0f;
    983     pdfUtil.addBarcode(scanbId, xBarcodeUpperLeft, yBarcodeUpperLeft, width, height, 0);
    984     textFontSize = 10.0f;
    985     float xTextUpperLeft = 92.2f;
    986     float yTextUpperLeft = yBarcodeUpperLeft - 10.0f;
    987     pdfUtil.addText(text, textFontSize, xTextUpperLeft, yTextUpperLeft);
    988 
    989     // Add blank extra page
    990     pdfUtil.newPage();
    991 
    992     return pdfUtil;
    993   }
    994 
    995   private PdfUtil7 createBiopsyClinChemForm(DbControl dc, PdfUtil7 pdfUtil, String scanbId, List<String> formTemplateFileList)
    996     throws IOException
    997   {   
    998     return createClinChemForm(dc, pdfUtil, scanbId, REF_FORM_TEMPLATE_CLIN_CHEM_BIOPSY, formTemplateFileList);
    999   }
    1000 
    1001   private PdfUtil7 createClinChemForm(DbControl dc, PdfUtil7 pdfUtil, String scanbId, List<String> formTemplateFileList)
    1002     throws IOException
    1003   {   
    1004     return createClinChemForm(dc, pdfUtil, scanbId, REF_FORM_TEMPLATE_CLIN_CHEM, formTemplateFileList);
    1005   }
    1006 
    1007   private PdfUtil7 createClinChemForm(DbControl dc, PdfUtil7 pdfUtil, String scanbId, String formTemplateName, List<String> formTemplateFileList)
    1008     throws IOException
    1009   {   
    1010     // Get PDF templates of same type
    1011     List<File> pdfFiles = fetchReferralFormTemplateFileList(dc, scanbId, formTemplateName);
    1012     for (File pdfFile: pdfFiles)
    1013     {
    1014       pdfUtil = createClinChemForm(dc, pdfUtil, pdfFile, scanbId, formTemplateName, formTemplateFileList);
    1015     }
    1016 
    1017     return pdfUtil;
    1018   }
    1019 
    1020   private PdfUtil7 createClinChemForm(DbControl dc, PdfUtil7 pdfUtil, File pdfFile, String scanbId, String formTemplateName, List<String> formTemplateFileList)
    1021     throws IOException
    1022   {   
    1023     if (pdfFile == null)
    1024     {
    1025       return pdfUtil;
    1026     }
    1027     if (!formTemplateFileList.contains(pdfFile.getName()))
    1028     {
    1029       formTemplateFileList.add(pdfFile.getName());
    1030     }
    1031     InputStream pdfInStream = pdfFile.getDownloadStream(0);
    1032     pdfUtil.newPage();
    1033     // Import PDF document template
    1034     float xOrig = 28.1f;
    1035     float yOrig = 15.9f;
    1036     float scaleX = 0.998f;
    1037     float scaleY = 0.997f;
    1038     int pageNo = 1;
    1039     pdfUtil.importPdf(pdfInStream, pageNo, xOrig, yOrig, Float.NaN, Float.NaN, Align.LEFT);
    1040 
    1041     // SCAN-B ID below bar code in upper right section
    1042     String text = "SCAN-B " + scanbId;
    1043     float textFontSize = 11.9f;
    1044     float xTextUpperRight = 448.0f;
    1045     float yTextUpperRight = 651.0f;
    1046     if (formTemplateName != null && formTemplateName.equals(REF_FORM_TEMPLATE_CLIN_CHEM_BIOPSY))
    1047     {
    1048       xTextUpperRight = 443.0f;
    1049     }
    1050     pdfUtil.addText(text, textFontSize, xTextUpperRight, yTextUpperRight, boldText);
    1051 
    1052     // Barcode at upper right
    1053     float xBarcodeUpperRight = xTextUpperRight + 0.7f;
    1054     float yBarcodeUpperRight = yTextUpperRight + 12.0f;
    1055     float width = 94.1f;
    1056     float height = 20.0f;
    1057     if (formTemplateName != null && formTemplateName.equals(REF_FORM_TEMPLATE_CLIN_CHEM_BIOPSY))
    1058     {
    1059       width = 105.8f;
    1060       xBarcodeUpperRight = xTextUpperRight - 0.2f;
    1061     }
    1062     pdfUtil.addBarcode(scanbId, xBarcodeUpperRight, yBarcodeUpperRight, width, height, 0);
    1063 
    1064     // Barcode and text at upper left
    1065     text = scanbId;
    1066     float xBarcodeUpperLeft = 65.2f;
    1067     float yBarcodeUpperLeft = 707.0f;
    1068     pdfUtil.addBarcode(scanbId, xBarcodeUpperLeft, yBarcodeUpperLeft, width, height, 0);
    1069     textFontSize = 10.0f;
    1070     float xTextUpperLeft = 92.5f;
    1071     float yTextUpperLeft = yBarcodeUpperLeft - 10.0f;
    1072     if (formTemplateName != null && formTemplateName.equals(REF_FORM_TEMPLATE_CLIN_CHEM_BIOPSY))
    1073     {
    1074       xTextUpperLeft = 95.5f;
    1075     }
    1076     pdfUtil.addText(text, textFontSize, xTextUpperLeft, yTextUpperLeft);
    1077 
    1078     // SCAN-B ID on both short sides of labels
    1079     textFontSize = 7.0f;
    1080     float xTextLowerLeft = 56.8f;
    1081     float yTextLowerLeft = 146.9f;
    1082     float yTextLowerLeft2 = yTextLowerLeft - 117.4f;
    1083     float xLowerLeftDiff = 55.6f;
    1084     // Extra correction term specific for each label
    1085     float[] xDiffSpecArr = new float[9];
    1086     xDiffSpecArr[0] = 0.0f;
    1087     xDiffSpecArr[1] = 0.0f;
    1088     xDiffSpecArr[2] = 0.0f;
    1089     xDiffSpecArr[3] = 0.5f;
    1090     xDiffSpecArr[4] = 1.5f;
    1091     xDiffSpecArr[5] = 3.5f;
    1092     xDiffSpecArr[6] = 4.0f;
    1093     xDiffSpecArr[7] = 3.5f;
    1094     xDiffSpecArr[8] = 0.5f;
    1095     if (formTemplateName != null && formTemplateName.equals(REF_FORM_TEMPLATE_CLIN_CHEM_BIOPSY))
    1096     {
    1097       xDiffSpecArr[0] = -3.5f;
    1098       xDiffSpecArr[8] = 4.0f;
    1099     }
    1100 
    1101     for (int i = 0; i < 7; i++)
    1102     {
    1103       float xTextLowerLeft2 = xTextLowerLeft + i*xLowerLeftDiff + xDiffSpecArr[i];
    1104       pdfUtil.addText(text, textFontSize, xTextLowerLeft2, yTextLowerLeft, boldText);
    1105       pdfUtil.addText(text, textFontSize, xTextLowerLeft2, yTextLowerLeft2, boldText);
    1106     }
    1107     //
    1108     //pdfUtil.drawGrid();
    1109 
    1110     // Barcode on labels
    1111     float labelBarcodeWidth = 61.7f;
    1112     float labelBarcodeHeight = 13.5f;
    1113     float rotationDegrees = 90.0f;
    1114     float xLabelBarcodeLeft = 67.8f;
    1115     float yLabelBarcodeLeft = 43.5f;
    1116     Options boldRotated = new Options(Align.LEFT).bold().rotation(90);
    1117     for (int i = 0; i < 9; i++)
    1118     {
    1119       float xLabelBarcodeLeft2 = xLabelBarcodeLeft + i*xLowerLeftDiff + xDiffSpecArr[i];
    1120       pdfUtil.addBarcode(scanbId, xLabelBarcodeLeft2, yLabelBarcodeLeft, labelBarcodeWidth, labelBarcodeHeight, rotationDegrees);
    1121       // Barcode label text
    1122       String labelText = "SCAN-B " + scanbId;
    1123       float xLabelTextLeft = xLabelBarcodeLeft2 + 24.0f;
    1124       float yLabelTextLeft = yLabelBarcodeLeft - 2.0f;
    1125       float labelTextFontSize = 10.0f;
    1126       pdfUtil.addText(labelText, labelTextFontSize, xLabelTextLeft, yLabelTextLeft, boldRotated);
    1127     }
    1128 
    1129     return pdfUtil;
    1130   }
    1131 
    1132   private PdfUtil7 createMiddleNeedleBiopsyForm(DbControl dc, PdfUtil7 pdfUtil, String scanbId, List<String> formTemplateFileList)
    1133     throws IOException
    1134   {   
    1135     return createClinPathologyForm(dc, pdfUtil, scanbId, REF_FORM_TEMPLATE_MIDDLE_NEEDLE_BIOPSY, formTemplateFileList);
    1136   }
    1137 
    1138   private PdfUtil7 createClinPathologyForm(DbControl dc, PdfUtil7 pdfUtil, String scanbId, List<String> formTemplateFileList)
    1139     throws IOException
    1140   {   
    1141     return createClinPathologyForm(dc, pdfUtil, scanbId, REF_FORM_TEMPLATE_CLIN_PATHOLOGY, formTemplateFileList);
    1142   }
    1143 
    1144   private PdfUtil7 createClinPathologyForm(DbControl dc, PdfUtil7 pdfUtil, String scanbId, String formTemplateName, List<String> formTemplateFileList)
    1145     throws IOException
    1146   {   
    1147     // Get PDF templates of same type
    1148     List<File> pdfFiles = fetchReferralFormTemplateFileList(dc, scanbId, formTemplateName);
    1149     for (File pdfFile: pdfFiles)
    1150     {
    1151       pdfUtil = createClinPathologyForm(dc, pdfUtil, pdfFile, scanbId, formTemplateName, formTemplateFileList);
    1152     }
    1153 
    1154     return pdfUtil;
    1155   }
    1156 
    1157   private PdfUtil7 createClinPathologyForm(DbControl dc, PdfUtil7 pdfUtil, File pdfFile, String scanbId, String formTemplateName, List<String> formTemplateFileList)
    1158     throws IOException
    1159   {   
    1160     if (pdfFile == null)
    1161     {
    1162       return pdfUtil;
    1163     }
    1164     if (!formTemplateFileList.contains(pdfFile.getName()))
    1165     {
    1166       formTemplateFileList.add(pdfFile.getName());
    1167     }
    1168     InputStream pdfInStream = pdfFile.getDownloadStream(0);
    1169     pdfUtil.newPage();
    1170     // Import PDF document template
    1171     float xOrig = 28.1f;
    1172     float yOrig = 15.9f;
    1173     float scaleX = 0.998f;
    1174     float scaleY = 0.997f;
    1175     int pageNo = 1;
    1176     pdfUtil.importPdf(pdfInStream, pageNo, xOrig, yOrig, Float.NaN, Float.NaN, Align.LEFT);
    1177 
    1178     // SCAN-B ID below bar code in upper right section
    1179     String text = "SCAN-B " + scanbId;
    1180     float textFontSize = 11.9f;
    1181     float xTextUpperRight = 448.0f;
    1182     float yTextUpperRight = 651.0f;
    1183     if (formTemplateName != null && formTemplateName.equals(REF_FORM_TEMPLATE_MIDDLE_NEEDLE_BIOPSY))
    1184     {
    1185       xTextUpperRight = 443.0f;
    1186     }
    1187     pdfUtil.addText(text, textFontSize, xTextUpperRight, yTextUpperRight, boldText);
    1188 
    1189     // Barcode at upper right
    1190     float xBarcodeUpperRight = xTextUpperRight + 0.7f;
    1191     float yBarcodeUpperRight = yTextUpperRight + 12.0f;
    1192     float width = 94.1f;
    1193     float height = 20.0f;
    1194     if (formTemplateName != null && formTemplateName.equals(REF_FORM_TEMPLATE_MIDDLE_NEEDLE_BIOPSY))
    1195     {
    1196       width = 105.8f;
    1197       xBarcodeUpperRight = xTextUpperRight - 0.2f;
    1198     }
    1199     pdfUtil.addBarcode(scanbId, xBarcodeUpperRight, yBarcodeUpperRight, width, height, 0);
    1200 
    1201     // Barcode and text at upper left
    1202     text = scanbId;
    1203     float xBarcodeUpperLeft = 65.2f;
    1204     float yBarcodeUpperLeft = 707.0f;
    1205     pdfUtil.addBarcode(scanbId, xBarcodeUpperLeft, yBarcodeUpperLeft, width, height, 0);
    1206     textFontSize = 10.0f;
    1207     float xTextUpperLeft = 92.5f;
    1208     float yTextUpperLeft = yBarcodeUpperLeft - 10.0f;
    1209     if (formTemplateName != null && formTemplateName.equals(REF_FORM_TEMPLATE_MIDDLE_NEEDLE_BIOPSY))
    1210     {
    1211       xTextUpperLeft = 95.5f;
    1212     }
    1213     pdfUtil.addText(text, textFontSize, xTextUpperLeft, yTextUpperLeft);
    1214 
    1215     // Barcode on labels (short side)
    1216     float labelBarcodeWidth = 44.5f;
    1217     float labelBarcodeHeight = 14.4f;
    1218     float rotationDegrees = 0.0f;
    1219     float xLabelBarcodeLeft = 48.7f;
    1220     float yLabelBarcodeLeft = 145.0f;
    1221     float yLabelBarcodeLeft2 = yLabelBarcodeLeft - 120.7f;
    1222     float xLowerLeftDiff = 56.6f;
    1223     for (int i = 0; i < 6; i++)
    1224     {
    1225       float xLabelBarcodeLeft2 = xLabelBarcodeLeft + i*xLowerLeftDiff;
    1226       pdfUtil.addBarcode(scanbId, xLabelBarcodeLeft2, yLabelBarcodeLeft, labelBarcodeWidth, labelBarcodeHeight, rotationDegrees);
    1227       pdfUtil.addBarcode(scanbId, xLabelBarcodeLeft2, yLabelBarcodeLeft2, labelBarcodeWidth, labelBarcodeHeight, rotationDegrees);
    1228       // Barcode label text
    1229       String labelText = scanbId;
    1230       float xLabelTextLeft = xLabelBarcodeLeft2 + 7.4f;
    1231       float yLabelTextLeft = yLabelBarcodeLeft - 7.0f;
    1232       float yLabelTextBottom = yLabelBarcodeLeft2 + labelBarcodeHeight + 2.0f;
    1233       float labelTextFontSize = 6.0f;
    1234       pdfUtil.addText(labelText, labelTextFontSize, xLabelTextLeft, yLabelTextLeft, boldText);
    1235       pdfUtil.addText(labelText, labelTextFontSize, xLabelTextLeft, yLabelTextBottom, boldText);
    1236     }
    1237 
    1238     // SCAN-B ID on long side of first six labels
    1239     String labelText = "SCAN-B " + scanbId;
    1240     float labelTextFontSize = 10.0f;
    1241     rotationDegrees = 90.0f;
    1242     float xLabelTextLeft = 72.5f;
    1243     float yLabelText = 48.8f;
    1244     Options boldRotated = new Options(Align.LEFT).bold().rotation(90);
    1245     for (int i = 0; i < 6; i++)
    1246     {
    1247       float xLabelText = xLabelTextLeft + i*xLowerLeftDiff;
    1248       if (i > 0 && i < 5)
    1249       {
    1250         xLabelText += 9.0f;
    1251       }
    1252       else if (i == 5)
    1253       {
    1254         xLabelText += 7.0f;         
    1255       }
    1256       pdfUtil.addText(labelText, labelTextFontSize, xLabelText, yLabelText, boldRotated);
    1257     }
    1258 
    1259     // Barcode on labels (long side)
    1260     labelBarcodeWidth = 61.2f;
    1261     labelBarcodeHeight = 21.4f;
    1262     rotationDegrees = 90.0f;
    1263     xLabelBarcodeLeft = 58.9f;
    1264     yLabelBarcodeLeft = 52.7f;
    1265     for (int i = 6; i < 9; i++)
    1266     {
    1267       if (formTemplateName != null && formTemplateName.equals(REF_FORM_TEMPLATE_MIDDLE_NEEDLE_BIOPSY))
    1268       {
    1269         if (i == 8)
    1270         {
    1271           xLabelBarcodeLeft -= 4.0f;
    1272         }
    1273       }
    1274       float xLabelBarcodeLeft2 = xLabelBarcodeLeft + i*xLowerLeftDiff;
    1275       pdfUtil.addBarcode(scanbId, xLabelBarcodeLeft2, yLabelBarcodeLeft, labelBarcodeWidth, labelBarcodeHeight, rotationDegrees);
    1276       // Barcode label text
    1277       labelText = "SCAN-B " + scanbId;
    1278       xLabelTextLeft = xLabelBarcodeLeft2 + 29.8f;
    1279       float yLabelTextLeft = yLabelBarcodeLeft - 7.9f;
    1280       pdfUtil.addText(labelText, labelTextFontSize, xLabelTextLeft, yLabelTextLeft, boldRotated);
    1281     }
    1282 
    1283     return pdfUtil;
    1284   }
    1285 
    1286   private PdfUtil7 createClinChemBloodForm(DbControl dc, PdfUtil7 pdfUtil, String scanbId, List<String> formTemplateFileList)
    1287     throws IOException
    1288   {   
    1289     return createClinChemBloodForm(dc, pdfUtil, scanbId, REF_FORM_TEMPLATE_CLIN_CHEM_BLOOD, formTemplateFileList);
    1290   }
    1291 
    1292   private PdfUtil7 createClinChemBloodLundCopyForm(DbControl dc, PdfUtil7 pdfUtil, String scanbId, List<String> formTemplateFileList)
    1293     throws IOException
    1294   {   
    1295     return createClinChemBloodForm(dc, pdfUtil, scanbId, REF_FORM_TEMPLATE_CLIN_CHEM_BLOOD_LUNDCOPY, formTemplateFileList);
    1296   }
    1297 
    1298   private PdfUtil7 createClinChemBloodForm(DbControl dc, PdfUtil7 pdfUtil, String scanbId, String formTemplateName, List<String> formTemplateFileList)
    1299     throws IOException
    1300   {   
    1301     // Get PDF templates of same type
    1302     List<File> pdfFiles = fetchReferralFormTemplateFileList(dc, scanbId, formTemplateName);
    1303     for (File pdfFile: pdfFiles)
    1304     {
    1305       pdfUtil = createClinChemBloodForm(dc, pdfUtil, pdfFile, scanbId, formTemplateFileList);
    1306     }
    1307 
    1308     return pdfUtil;
    1309   }
    1310 
    1311   private PdfUtil7 createClinChemBloodForm(DbControl dc, PdfUtil7 pdfUtil, File pdfFile, String scanbId, List<String> formTemplateFileList)
    1312     throws IOException
    1313   {   
    1314     if (pdfFile == null)
    1315     {
    1316       return pdfUtil;
    1317     }
    1318     if (!formTemplateFileList.contains(pdfFile.getName()))
    1319     {
    1320       formTemplateFileList.add(pdfFile.getName());
    1321     }
    1322     InputStream pdfInStream = pdfFile.getDownloadStream(0);
    1323     pdfUtil.newPage();
    1324     // Import PDF document template
    1325     float xOrig = 29.4f;
    1326     float yOrig = 14.2f;
    1327     float scaleX = 1.000f;
    1328     float scaleY = 1.000f;
    1329     int pageNo = 1;
    1330     pdfUtil.importPdf(pdfInStream, pageNo, xOrig, yOrig, Float.NaN, Float.NaN, Align.LEFT);
    1331 
    1332     // SCAN-B ID below bar code in upper right section
    1333     String text = "SCAN-B " + scanbId;
    1334     float textFontSize = 12.5f;
    1335     float xTextUpperRight = 435.0f;
    1336     float yTextUpperRight = 657.0f;
    1337     pdfUtil.addText(text, textFontSize, xTextUpperRight, yTextUpperRight, boldText);
    1338     //
    1339     //pdfUtil.drawGrid();
    1340 
    1341     // Barcode at upper right
    1342     float xBarcodeUpperRight = xTextUpperRight + 0.9f;
    1343     float yBarcodeUpperRight = yTextUpperRight + 12.0f;
    1344     float width = 96.1f;
    1345     float height = 20.0f;
    1346     pdfUtil.addBarcode(scanbId, xBarcodeUpperRight, yBarcodeUpperRight, width, height, 0);
    1347 
    1348     // Barcode at upper left
    1349     float xBarcodeUpperLeft = 64.9f;
    1350     float yBarcodeUpperLeft = 684.3f;
    1351     pdfUtil.addBarcode(scanbId, xBarcodeUpperLeft, yBarcodeUpperLeft, width, height, 0);
    1352     text = scanbId;
    1353     textFontSize = 10.0f;
    1354     float xTextUpperLeft = 93.0f;
    1355     float yTextUpperLeft = yBarcodeUpperLeft - 10.0f;
    1356     pdfUtil.addText(text, textFontSize, xTextUpperLeft, yTextUpperLeft);
    1357 
    1358     // Add blank extra page
    1359     pdfUtil.newPage();
    1360 
    1361     return pdfUtil;
    1362   }
    1363 
    1364   private PdfUtil7 createClinChemBcBloodForm(DbControl dc, PdfUtil7 pdfUtil, String scanbId, List<String> formTemplateFileList)
    1365     throws IOException
    1366   {   
    1367     return createClinChemBcBloodForm(dc, pdfUtil, scanbId, REF_FORM_TEMPLATE_CLIN_CHEM_BCBLOOD, formTemplateFileList);
    1368   }
    1369 
    1370   private PdfUtil7 createClinChemBcBloodForm(DbControl dc, PdfUtil7 pdfUtil, String scanbId, String formTemplateName, List<String> formTemplateFileList)
    1371     throws IOException
    1372   {   
    1373     // Get PDF templates of same type
    1374     List<File> pdfFiles = fetchReferralFormTemplateFileList(dc, scanbId, formTemplateName);
    1375     for (File pdfFile: pdfFiles)
    1376     {
    1377       pdfUtil = createClinChemBcBloodForm(dc, pdfUtil, pdfFile, scanbId, formTemplateFileList);
    1378     }
    1379 
    1380     return pdfUtil;
    1381   }
    1382 
    1383   private PdfUtil7 createClinChemBcBloodForm(DbControl dc, PdfUtil7 pdfUtil, File pdfFile, String scanbId, List<String> formTemplateFileList)
    1384     throws IOException
    1385   {   
    1386     if (pdfFile == null)
    1387     {
    1388       return pdfUtil;
    1389     }
    1390     if (!formTemplateFileList.contains(pdfFile.getName()))
    1391     {
    1392       formTemplateFileList.add(pdfFile.getName());
    1393     }
    1394     InputStream pdfInStream = pdfFile.getDownloadStream(0);
    1395     pdfUtil.newPage();
    1396     // Import PDF document template
    1397     float xOrig = 35.0f;
    1398     float yOrig = 10.0f;
    1399     float scaleX = 1.000f;
    1400     float scaleY = 1.000f;
    1401     int pageNo = 1;
    1402     pdfUtil.importPdf(pdfInStream, pageNo, xOrig, yOrig, Float.NaN, Float.NaN, Align.LEFT);
    1403 
    1404     // SCAN-B ID below bar code in upper right section
    1405     // Add hyphen between SCAN-B prefix and rest of index
    1406     String scanbPrefix = scanbId.substring(0,2);
    1407     String scanbResidue = scanbId.substring(2);
    1408     String text = "BC-BLOD " + scanbPrefix + "-" + scanbResidue;
    1409     float textFontSize = 9.7f;
    1410     float xTextUpperRight = 298.3f;
    1411     float yTextUpperRight = 678.0f;
    1412     pdfUtil.addText(text, textFontSize, xTextUpperRight, yTextUpperRight, boldText);
    1413 
    1414     // SCAN-B ID on both short sides of labels
    1415     text = scanbId;
    1416     textFontSize = 9.5f;
    1417     float xTextLowerLeft = 50.0f;
    1418     float yTextLowerLeft = 141.0f;
    1419     float yTextLowerLeft2 = yTextLowerLeft - 123.0f;
    1420     float xLowerLeftDiff = 57.2f;
    1421     // Right short side of label (label top in form)
    1422     for (int i = 0; i < 5; i++)
    1423     {
    1424       float xTextLowerLeft2 = xTextLowerLeft + i*xLowerLeftDiff;
    1425       pdfUtil.addText(text, textFontSize, xTextLowerLeft2, yTextLowerLeft, boldText);
    1426     }
    1427     textFontSize = 7.0f;
    1428     xTextLowerLeft = 57.0f;
    1429     yTextLowerLeft = 148.0f;
    1430     yTextLowerLeft2 = yTextLowerLeft - 123.0f;
    1431     // Left short side of label (label bottom in form)
    1432     for (int i = 0; i < 7; i++)
    1433     {
    1434       float xTextLowerLeft2 = xTextLowerLeft + i*xLowerLeftDiff;
    1435       pdfUtil.addText(text, textFontSize, xTextLowerLeft2, yTextLowerLeft2, boldText);
    1436     }
    1437     //
    1438     //pdfUtil.drawGrid();
    1439 
    1440     // Barcode at upper right
    1441     float xBarcodeUpperRight = xTextUpperRight;
    1442     float yBarcodeUpperRight = yTextUpperRight + 12.0f;
    1443     float width = 88.0f;
    1444     float height = 22.0f;
    1445     pdfUtil.addBarcode(scanbId, xBarcodeUpperRight, yBarcodeUpperRight, width, height, 0);
    1446 
    1447     // Barcode on labels
    1448     float labelBarcodeWidth = 55.4f;
    1449     float labelBarcodeHeight = 12.5f;
    1450     float rotationDegrees = 90.0f;
    1451     float xLabelBarcodeLeft = 62.0f;
    1452     float yLabelBarcodeLeft = 38.3f;
    1453     Options boldRotated = new Options(Align.LEFT).bold().rotation(90);
    1454     for (int i = 0; i < 9; i++)
    1455     {
    1456       float xLabelBarcodeLeft2 = xLabelBarcodeLeft + i*xLowerLeftDiff;
    1457       pdfUtil.addBarcode(scanbId, xLabelBarcodeLeft2, yLabelBarcodeLeft, labelBarcodeWidth, labelBarcodeHeight, rotationDegrees);
    1458       // Barcode label text
    1459       String labelText = "BC-BLOD " + scanbPrefix + "-" + scanbResidue;
    1460       float xLabelTextLeft = xLabelBarcodeLeft2 + 24.0f;
    1461       float yLabelTextLeft = yLabelBarcodeLeft + 5.0f;
    1462       float labelTextFontSize = 10.0f;
    1463       pdfUtil.addText(labelText, labelTextFontSize, xLabelTextLeft, yLabelTextLeft, boldRotated);
    1464     }
    1465 
    1466     return pdfUtil;
    1467   }
    1468123
    1469124  @Override
     
    1478133   
    1479134    JSONArray jsonMessages = new JSONArray();
    1480 
     135 
    1481136    final SessionControl sc = Reggie.getSessionControl(req);
    1482137    DbControl dc = null;
    1483     String progressId = "";
    1484   }
     138    try
     139    {
     140      if ("ExportToBD47".equals(cmd))
     141      {
     142        dc = sc.newDbControl();
     143        ReggieRole.checkPermission(dc, "'" + cmd + "' wizard", ReggieRole.PATIENT_CURATOR, ReggieRole.ADMINISTRATOR);
     144       
     145        boolean preview = Values.getBoolean(req.getParameter("preview"));
     146       
     147        JSONObject jsonReq = JsonUtil.parseRequest(req);
     148
     149        Site site = Site.findByCaseName((String)jsonReq.get("site"));
     150        String kitType = Values.getString((String)jsonReq.get("kitType"), "standard");
     151        int startNumber = ((Number)jsonReq.get("startNumber")).intValue();
     152        int numKits = Math.max(1, Math.min(100, ((Number)jsonReq.get("numKits")).intValue()));
     153       
     154        StringBuilder csv = new StringBuilder();
     155        String sep = ";";
     156        csv.append("RemissID"+sep+"Remisstyp"+sep+"Remissmottagare\n");
     157        RefType[] refs = getRefTypes(site, kitType);
     158        for (int kitNo = 0; kitNo < numKits; kitNo++)
     159        {
     160          for (RefType rt : refs)
     161          {
     162            csv.append(rt.getRow(startNumber+kitNo, site, sep)+"\n");
     163          }
     164        }
     165       
     166        if (preview)
     167        {
     168          json.put("csv", csv.toString());
     169        }
     170        else
     171        {
     172          // Save BD47 file
     173          int fileIndex = 1;
     174          File bd47 = null;
     175          while (true)
     176          {
     177            // Try to generate a file until we find a non-existing one
     178            String filename = Path.makeSafeFilename(Reggie.CONVERTER_DATE_TO_STRING_WITH_SEPARATOR.convert(new Date())+
     179              "_"+site.getName()+"_"+kitType+(fileIndex==1?"":"."+fileIndex)+".csv", "");
     180            Path p = new Path(Reggie.REFERRAL_LOGS_DIR+"/"+filename, Path.Type.FILE);
     181            bd47 = File.getByPath(dc, p, true);
     182            if (!bd47.isInDatabase()) break;
     183            fileIndex++;
     184          }
     185          bd47.setCharacterSet("UTF-8");
     186          bd47.setMimeType("text/plain");
     187          dc.saveItem(bd47);
     188         
     189          OutputStream out = bd47.getUploadStream(false);
     190          Writer writer = new OutputStreamWriter(out);
     191          writer.write(csv.toString());
     192          writer.flush();
     193          out.flush();
     194          FileUtil.close(writer);
     195          FileUtil.close(out);
     196         
     197          // Append to log file
     198          File log = appendToLogFile(dc, site, kitType, startNumber, numKits, bd47.getName());
     199         
     200          // Save recent settings
     201          ClientDefaultSetting lastReferralID = ClientApp.REGGIE.getSetting(dc, "last-referral-id", true);
     202          lastReferralID.setValue(Site.UNKNOWN.toScanbID(startNumber+numKits));
     203          ClientDefaultSetting lastNumKits = ClientApp.REGGIE.getSetting(dc, "last-referral-num-kits", true);
     204          lastNumKits.setValue(Integer.toString(numKits));
     205         
     206          dc.commit();
     207         
     208          jsonMessages.add("Generated "+numKits+" "+kitType+" kits for "+site.getName());
     209          jsonMessages.add("First SCAN-B ID: " + site.toScanbID(startNumber));
     210          jsonMessages.add("Last SCAN-B ID: " + site.toScanbID(startNumber+numKits-1));
     211         
     212          json.put("bd47File", bd47.getId());
     213          json.put("bd47Path", bd47.getPath().toString());
     214          json.put("logFile", log.getId());
     215        }
     216       
     217      }
     218      json.put("messages", jsonMessages);
     219    }
     220    catch (Throwable t)
     221    {
     222      t.printStackTrace();
     223      json.clear();
     224      json.put("status", "error");
     225      json.put("message", t.getMessage());
     226      json.put("stacktrace", ThrowableUtil.stackTraceToString(t));
     227    }
     228    finally
     229    {
     230      if (dc != null) dc.close();
     231      json.writeJSONString(resp.getWriter());
     232    }
     233   
     234  }
     235 
     236  private File appendToLogFile(DbControl dc, Site site, String kitType, int startNumber, int numKits, String fileName)
     237    throws IOException
     238  {
     239    Path logPath = new Path(Reggie.REFERRAL_LOGS_DIR+"/referral-id-generator.log", Path.Type.FILE);
     240    File log = File.getByPath(dc, logPath, true);
     241    InputStream in = null;
     242    OutputStream out = null;
     243    int[] colSizes = { 20, 10, 10, 15, 15, 10, -1 };
     244    try
     245    {
     246      if (!log.isInDatabase())
     247      {
     248        log.setDescription("Log file for the Referral ID generator wizard");
     249        log.setCharacterSet("UTF-8");
     250        log.setMimeType("text/plain");
     251        dc.saveItem(log);
     252      }
     253      else
     254      {
     255        in = log.getDownloadStream(0);
     256      }
     257     
     258      out = log.getUploadStream(false);
     259     
     260      Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8);
     261      String[] header = new String[] { "DateAndTime", "Start", "End", "Site", "KitType", "NumKits", "FileName" };
     262      writeRow(writer, header, colSizes);
     263         
     264      String[] row = new String[] {
     265        Reggie.CONVERTER_DATETIME_TO_STRING_WITH_SEPARATOR.convert(new Date()),
     266        site.toScanbID(startNumber), site.toScanbID(startNumber+numKits-1),
     267        site.getName(), kitType, Integer.toString(numKits), fileName
     268        };
     269      writeRow(writer, row, colSizes);
     270     
     271      if (in != null)
     272      {
     273        // Copy rest of original file except the header line
     274        BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
     275        reader.readLine();
     276        FileUtil.copy(reader, writer);
     277      }
     278     
     279      writer.flush();
     280      out.flush();
     281    }
     282    finally
     283    {
     284      FileUtil.close(out);
     285      FileUtil.close(in);
     286    }
     287    return log;
     288  }
     289 
     290  private void writeRow(Writer writer, String[] row, int[] colSizes)
     291    throws IOException
     292  {
     293    StringBuilder sb = new StringBuilder(row[0]);
     294    int col = colSizes[0];
     295    for (int i = 1; i < row.length; i++)
     296    {
     297      int padding = col-sb.length();
     298      sb.append(" ".repeat(Math.max(1, padding)));
     299      sb.append(row[i]);
     300      col += colSizes[i];
     301    }
     302    writer.write(sb.toString());
     303    writer.write('\n');
     304  }
     305 
     306  private RefType[] getRefTypes(Site s, String kitType)
     307  {
     308    RefType[] refTypes = new RefType["neoadjuvant".equals(kitType) ? 3 : 2];
     309    refTypes[0] = RefType.KLIN_PAT;
     310    if (s == Site.HALMSTAD)
     311    {
     312      refTypes[1] = RefType.KLIN_KEM_33;
     313      if (refTypes.length > 2) refTypes[2] = RefType.KLIN_KEM_NEO_33;
     314    }
     315    else if (s == Site.JÖNKÖPING)
     316    {
     317      refTypes[1] = RefType.KLIN_KEM_99;
     318      if (refTypes.length > 2) refTypes[2] = RefType.KLIN_KEM_NEO_99;
     319    }
     320    else
     321    {
     322      refTypes[1] = RefType.KLIN_KEM;
     323      if (refTypes.length > 2) refTypes[2] = RefType.KLIN_KEM_NEO;
     324    }
     325    return refTypes;
     326  }
     327 
     328  public static enum RefType
     329  {
     330    KLIN_PAT("SCAN-B KlinPat", "", ""),
     331    KLIN_KEM("SCAN-B KlinKem", "K", ""),
     332    KLIN_KEM_NEO("SCAN-B KlinKemNeo", "K", "C"),
     333    KLIN_KEM_33("SCAN-B KlinKem33", "K", ""),
     334    KLIN_KEM_NEO_33("SCAN-B KlinKemNeo33", "K", "C"),
     335    KLIN_KEM_99("SCAN-B KlinKem99", "K", ""),
     336    KLIN_KEM_NEO_99("SCAN-B KlinKemNeo99", "K", "C");
     337   
     338    private final String typeName;
     339    private final String prefix;
     340    private final String suffix;
     341   
     342    RefType(String typeName, String prefix, String suffix)
     343    {
     344      this.typeName = typeName;
     345      this.prefix = prefix;
     346      this.suffix = suffix;
     347    }
     348   
     349    public String getRow(int scanbNumber, Site s, String sep)
     350    {
     351      return prefix+s.toScanbID(scanbNumber)+suffix + sep + typeName + sep + s.getName();
     352    }
     353  }
     354 
    1485355}
Note: See TracChangeset for help on using the changeset viewer.