/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
 
//Source code Copyright (c) 2018 AtomJump Ltd. (New Zealand)
//IMPORTANT: Any changes to this file, and you should create a publishable version in the js/pub folder, with a version number attached to prevent client caching.
//Update the version number in index.php around line 576:
// <script type="text/javascript" src="js/pub/index-2-4-0.js"></script> <!-- Update number for new version to prevent caching -->


var deleteThisFile = {}; //Global object for image taken, to be deleted
var centralPairingUrl = "https://medimage-pair.atomjump.com/med-genid.php";		//Redirects to an https connection. In future try setting to http://atomjump.org/med-genid.php
var glbThis = {};  //Used as a global error handler
var retryIfNeeded = [];	//A global pushable list with the repeat attempts
var checkComplete = [];	//A global pushable list with the repeat checks to see if image is on PC
var checkConnected = 0;		//Global count of checking photos taken before we are connected
var retryNum = 0;
var currentPhotoData = "";		//A temporary store for the current photo



//See: https://stackoverflow.com/questions/14787705/phonegap-cordova-filetransfer-abort-not-working-as-expected
// basic implementation of hash map of FileTransfer objects
// so that given a key, an abort function can find the right FileTransfer to abort
function SimpleHashMap()
{
    this.items = {};
    this.setItem = function(key, value) { this.items[key] = value; }
    this.getItem = function(key)
                   {
                       if (this.hasItem(key)) { return this.items[key]; }
                       return undefined;                    
                   }
    this.hasItem = function(key) { return this.items.hasOwnProperty(key); }
    this.removeItem = function(key)
                      {
                          if (this.hasItem(key)) { delete this.items[key]; }
                      }
}
var fileTransferMap = new SimpleHashMap(); 



  




var app = {


    // Application Constructor
    initialize: function() {

	

		glbThis = this;
        this.bindEvents();  
        
        //Check if we are still transitioning any data over from localStorage to cookies
    	this.checkTransitioningData();	
    	
    	//Check if we are doing an annual refresh of the cookies
    	this.refreshCookies();
    	    
        //Set display name
        this.displayServerName();
        
        //Initialise the id field
        this.displayIdInput();
        
        //Get a current photo id that increments after each photo
        if(localStorageGetItem("currentPhotoId")) {
        	this.currentPhotoId = parseInt(localStorageGetItem("currentPhotoId"));
        } else {
        	this.currentPhotoId = 0;
        	localStorageSetItem("currentPhotoId", this.currentPhotoId);
        }
       
        //Check if there are any residual photos that need to be sent again
        glbThis.loopLocalPhotosData();
        

    },
    // Bind Event Listeners
    //
    // Bind any events that are required on startup. Common events are:
    // 'load', 'deviceready', 'offline', and 'online'.
    bindEvents: function() {
        document.addEventListener('deviceready', this.onDeviceReady, false);
    },
    // deviceready Event Handler
    //
    // The scope of 'this' is the event. In order to call the 'receivedEvent'
    // function, we must explicity call 'app.receivedEvent(...);'
    onDeviceReady: function() {
          app.receivedEvent('deviceready');
          
          
        
    	 
          
          
    },
    
    
    // Update DOM on a Received Event
    receivedEvent: function(id) {
        var parentElement = document.getElementById(id);
		if(parentElement) {
			var listeningElement = parentElement.querySelector('.listening');
			var receivedElement = parentElement.querySelector('.received');

			listeningElement.setAttribute('style', 'display:none;');
			receivedElement.setAttribute('style', 'display:block;');
			console.log('Received Event: ' + id);
		} else {
			console.log('Failed Received Event: ' + id);
		}
		
        
    },
    
    processPictureData: function(imageDataLocalFile)
    {
    
 
        
        
        
        
        var _this = this;
        glbThis = this;
      
        //Keep a local increment ID of the photo on this browser
      	_this.currentPhotoId = _this.currentPhotoId + 1;
        localStorageSetItem("currentPhotoId", _this.currentPhotoId);
        var imageId = _this.currentPhotoId;
      
    	  //Called from takePicture(), after the image file URI has been shifted into a persistent file
          //Reconnect once
      	  localStorageRemoveItem("usingServer");		//This will force a reconnection
	      localStorageRemoveItem("defaultDir");
      	  
      	  var thisImageLocalFile = imageDataLocalFile;
      	  var idEntered = document.getElementById("id-entered").value;
       	 
        	  	   	 
		   _this.findServer(function(err) {
				if(err) {
					//So, we shouldn't have a valid usingServer entry at this point.
					glbThis.notify("Sorry, we cannot connect to the server. Trying again in 10 seconds.");
					glbThis.cancelNotify("<ons-icon style=\"vertical-align: middle; color:#f7afbb;\" size=\"30px\" icon=\"fa-close\" href=\"#javascript\" onclick=\"app.stopConnecting('" + imageId + "');\"></ons-icon><br/>Cancel");
					
					//Search again in 10 seconds:
					var passedImageFile = thisImageLocalFile;  
					var idEnteredB = idEntered;
					var thisScope = {};
			
			
		
			   		thisScope.imageId = imageId;
 					thisScope.imageData = passedImageFile;		
					thisScope.idEnteredB = idEnteredB;
					thisScope.newFilename = "";		//Cannot yet determine this as we don't know the target folder
					
					
 				  	//Store in case the app quits unexpectably
				   	_this.recordLocalPhotoData(thisScope.imageId, thisImageLocalFile, idEntered, thisScope.newFilename);
					
					glbThis.continueConnectAttempts = true;
				    setTimeout(function() {
				    	if(glbThis.continueConnectAttempts == true) {
				    		glbThis.notify("Trying to connect again.");
							localStorageRemoveItem("usingServer");		//This will force a reconnection
							localStorageRemoveItem("defaultDir");
							glbThis.uploadPhotoData(thisScope.imageId, passedImageFile, idEnteredB, thisScope.newFilename);
						}
					}, 10000);
					
					//Countdown
					var cntDown = 10;
					glbThis.cntLoopB = setInterval(function() {
						cntDown --;
						if(cntDown <= 0) {
								clearInterval(glbThis.cntLoopB);				
						}
						if((!glbThis.cntLoopA) && (cntDown >= 0) && (glbThis.continueConnectAttempts == true)) {	
							//Only show if the other loop is not running too
							glbThis.notify("Sorry, we cannot connect to the server. Trying again in " + cntDown + " seconds.");
						}
					},1000);	
					
					
					
			
					
					
				} else {
					//Now we are connected (and 'usingServer' should be set) - so we can get the filename
					_this.determineFilenameData(idEntered, function(err, newFilename) {
	
	   
					   if(err) {
							//There was a problem getting the filename from the disk file
							glbThis.notify("Sorry, we cannot process the filename of the photo " + idEntered + ". If this happens consistently, please report the problem to medimage.co.nz");
	   
					   } else {
		 					
		 				  //Store in case the app quits unexpectably
						   _this.recordLocalPhotoData(imageId, thisImageLocalFile, idEntered, newFilename);
		
		
							//Now we are connected, upload the photo again
							glbThis.uploadPhotoData(imageId, thisImageLocalFile, idEntered, newFilename);
						}
					});
				}
		  });
			  
       	  
       	  
      	 
	},

    
    
 

    takePicture: function() {
      var _this = this;
      glbThis = this;
      
      if(this.takingPhoto && this.takingPhoto == true) {
      	return;			//We should only have one camera up at a time.
      }
      this.takingPhoto = true;

      navigator.camera.getPicture( function( imageData ) {
      	 
      	 //Write the resulting image data into an element
      	 var imagePNG = document.getElementById('myImage');
      	 var fullBase64png = "data:image/png;base64," + imageData;
    	 imagePNG.src = fullBase64png;
    	 
    	imagePNG.onload = function () {
            var canvas = document.createElement("canvas");
            var ctx = canvas.getContext('2d');

            canvas.width = imagePNG.width;
            canvas.height = imagePNG.height;

            ctx.drawImage(imagePNG, 0, 0);       // draw the image to the canvas
            
            var fullBase64 = canvas.toDataURL("image/jpeg");			//Get the actual data in .jpg format
            
            
            
            
            glbThis.processPictureData(fullBase64); 
            _this.takingPhoto = false;		//Have finished with the camera
        }
    	
 
    
        },
       function( message ) {
       	 //An error or cancellation
         glbThis.notify( message );
       },
       {
        quality: 100,
        destinationType: Camera.DestinationType.DATA_URL,
        cameraDirection: 0,
        targetHeight: 2000,
        targetWidth: 3555
       });
    },
    
 
     recordLocalPhotoData: function(imageId, imageData, idEntered, fileName) {
    	 //Save into our local indexDb array, in case the app quits
    	 
    	 //Storing the cache of recent photos sent/unsent
    	 //IndexedDB seems like the best option: https://www.w3.org/TR/IndexedDB/ 
    	 //https://caniuse.com/indexeddb
    	 //The limits on storage size should be fine - almost no limits, although go past 5MB on some platforms
    	 //and it will give you a warning. See https://stackoverflow.com/questions/5692820/maximum-item-size-in-indexeddb
 
     	 
 		if(glbThis.idbSupported == true) {
			 glbThis.tx = glbThis.medImageSendCacheDb.transaction("images", "readwrite");
			 var store = glbThis.tx.objectStore("images");

			store.put({ imageId: imageId, imageData: imageData, idEntered: idEntered, fileName: fileName, status: "send"});

			glbThis.tx.oncomplete = function() {
			  // All requests have succeeded and the transaction has committed.
			}
		}
	 
    	return true;
    },
 
    

    
    arrayRemoveNulls: function(arr) {
		var newArray = [];

		for(var cnt = 0; cnt < arr.length; cnt++) {
			if(arr[cnt] && arr[cnt] != null) {
				newArray.push(arr[cnt]);
			}
   		}
   		
   		return newArray;

	},
	
	removeLocalPhoto: function(imageId) {
		//Loop through the current array and remove
		
		if(glbThis.idbSupported == true) {
		 	var tx = glbThis.medImageSendCacheDb.transaction("images", "readwrite");
		 	var store = tx.objectStore("images");
		
			store.delete(imageId);
		
			tx.oncomplete = function() {
			  // All requests have succeeded and the transaction has committed.
			};
		}
		
	
	},
    
    changeLocalPhotoStatus: function(imageId, newStatus, fullData) {
    	//Input:
    	//imageId  - unique image ID on browser
    	//newStatus can be 'send', 'onserver', 'sent' (usually deleted from the array), or 'cancel' 
    	//If onserver, the optional parameter 'fullGet', is the URL to call to check if the file is back on the server
    	
    	//Note: during the cancel, each removeLocalPhoto could occur at any time (async) depending on the filesystem speed,
    	//so the removeLocalPhoto does a sync load, delete from array, and write back.
    	
    	if(glbThis.idbSupported == true) {
	  		var tx = glbThis.medImageSendCacheDb.transaction("images", "readwrite");
			var store = tx.objectStore("images");
			
			var toUpdate = store.get(imageId);
			
			toUpdate.onsuccess = function() {
				if(toUpdate && toUpdate.result) {		//Not sure about this line - added because I was getting an error in one circumstance, but TODO: ensure
														//nothing is lost in this case.
					toUpdate.result.status = newStatus;
					
					if((newStatus == "onserver")&&(fullData)) {
						toUpdate.result.fullData = fullData;			
					}
					
					store.put(toUpdate.result);
				}
			}
		}
					
		if(newStatus === "cancel") {
			//Now remove local photo
			glbThis.removeLocalPhoto(imageId);
		}
 	
    	
    	tx.oncomplete = function() {
		  // All requests have succeeded and the transaction has committed.
		};
      
    },
    
    
    loopLocalPhotosData: function() {
     
      	//Get a photo, one at a time, in the array format:
      	/* {
      						"imageId" : imageId,
       	  					"imageData" : imageData,
       	  					"idEntered" : idEntered,
       	  					"fileName" : fileName,
       	  					"fullData" : fullDataObject - optional
       	  					"status" : "send"
       	  					};		//Status can be 'send', 'onserver', 'sent' (usually deleted from the array), or 'cancel' 
       	
       	and attempt to upload them.
       	*/
      	var photoDetails = null;
      	
      	if(glbThis.idbSupported == true) {
      	
		  	var tx = glbThis.medImageSendCacheDb.transaction("images", "readwrite");
			var store = tx.objectStore("images");
			
			
			var request = tx.objectStore("images").openCursor();
		 	request.onsuccess = function(e) {   
			   var cursor = request.result || e.result;             
			   if(cursor && cursor.value){             
				     
				  
				  var newPhoto = cursor.value;
				  
				  //Now our logic
				  if(newPhoto.status == 'onserver') {
		  				
		   				//OK - so it was successfully put onto the server. Recheck to see if it needs to be uploaded again
		  				if(newPhoto.fullData) {
		  					
		  					try {
		  						var fullData = newPhoto.fullData;
		  						if(fullData.details && fullData.details.imageData) {
		  							fullData.loopCnt = 11;
		  							fullData.slowLoopCnt = null;		//Start again with a quick loop
			  						checkComplete.push(fullData);
			  						var thisImageId = fullData.details.imageId;
			  						
			  						glbThis.check(thisImageId);		//This will only upload again if it finds it hasn't been transferred off the 
			  					} else {
			  						//This is a case where full details are not available. Do nothing.
				  					glbThis.changeLocalPhotoStatus(newPhoto.imageId, "cancel");
			  					}
		  					} catch(err) {
		  						//There was a problem parsing the data.
		   						glbThis.changeLocalPhotoStatus(newPhoto.imageId, "cancel");
		  					}
		  				} else {
		  					//No fullData was added - resend anyway
		  					glbThis.changeLocalPhotoStatus(newPhoto.imageId, "cancel");
		  				
		  				}
		  					
		  			
		  			} else {
		    			//Needs to be resent
		    			glbThis.uploadPhotoData(newPhoto.imageId, newPhoto.imageData, newPhoto.idEntered, newPhoto.fileName);
		    		}
		    		
		    		
				  cursor.continue();
			   }
		   } 
		  	
		  	tx.oncomplete = function(e) {
	   		}
	   	}	//End of idbSupported check
    	
     	
    	
    	return;
    
    }, 
    
    
   
    
    

   get: function(url, cb) {
   		var alreadyReturned = false;
        var request = new XMLHttpRequest();
        request.open("GET", url, true);
   
   		var getTimeout = setTimeout(function() {
   			if(alreadyReturned == false) {				//Don't double up with onerror
   				alreadyReturned = true;
            	cb(url, null, "timeout");   // Assume it hasn't gone through - we have a 404 error checking the server
            }
        }, 5000);
   			
                	
   
        request.onreadystatechange = function() {
            if (request.readyState == 4) {

                if (request.status == 200 || request.status == 0) {
					clearTimeout(getTimeout);
					if(alreadyReturned == false) {
						alreadyReturned = true;
                    	cb(url, request.responseText);   // -> request.responseText <- is a result
                    }		
                    
                } else {
                	if(alreadyReturned == false) {				//Don't double up with onerror
                		alreadyReturned = true;
                		cb(url, null);	
                	}
                }
            }
        }
        request.onerror = function() {
        	if (request.status != 200) {
        		if(alreadyReturned == false) {		//Don't double up with timeout
        			clearTimeout(getTimeout);
        			alreadyReturned = true;
        			cb(url, null);
        		}
        	}			
        }
        request.send();
    },

    scanlan: function(port, cb) {
      var _this = this;

		
		


      if(_this.lan) {

       var lan = _this.lan;

	   totalScanned = 0;
	   
	 
	   if(lan == "127.0.0.") {
	   		//Use the default 127.0.0.1 address, or there is no IP address e.g. a domain like localhost
	   		var machine = "1";
	   		var url = 'http://' + lan + machine + ':' + port;
	   		var scanMessage = lan;
	   		var waitForScan = 2000;
	   		
	   		this.get(url, function(goodurl, resp, timeout) {
	          
	          if(resp) {
	          	
	          	//This is a good server
				totalScanned ++;
							  
							  
				 //Save the first TODO: if more than one, open another screen here
				 localStorageSetItem("currentWifiServer", goodurl);
			 
				 clearInterval(scanning);
				 cb(goodurl, null);
	          } else {
	          	
				totalScanned ++;
				_this.notify("Scanning Wifi. Responses:" + totalScanned);
	          	
	          }
	          
	          
	      });
	   } else {
	   
	   	   var re = /^[A-Za-z]+$/;		//Regular expression for testing if letters
	   	  	
	   	   if( re.test(lan) == true) {
	   	   	 	//A letter-based domain e.g. localhost, mydomain.com.
	   	   	 	
	   	   	 	
	   	   	 	//Only want to scan this machine itself on the 5566 port
	   	   	 	var host = window.location.host;
	   	   	 	host = host.substring(0, host.indexOf(':'));		//Remove port
	   	   	 	var url = host + ':' + port;
	   	   	 	if(location.protocol) {
	   	   	 		if(url.indexOf(location.protocol) != true) {
	   	   	 			//Add http or https to the start
	   	   	 			url = location.protocol + "//" + url;
	   	   	 		}
	   	   	 	}
	   	   	 	var scanMessage = lan;
	   	   	 	var waitForScan = 2000;
	   	   	 	
	   	   	 	this.get(url, function(goodurl, resp, timeout) {
	          
			      if(resp) {
			      	
			      	//This is a good server
					totalScanned ++;
								  
								  
					 //Save the first TODO: if more than one, open another screen here
					 localStorageSetItem("currentWifiServer", goodurl);
				 
					 clearInterval(scanning);
					 cb(goodurl, null);
			      } else {
			      	
					totalScanned ++;
					_this.notify("Scanning Wifi. Responses:" + totalScanned);
			      	
			      }
			   });
	   	   
	   	   } else {
	   	   
	   	   	   //Do a full LAN scan
	   	   	   
	   	   	   var scanMessage = "http://" + lan + "[range of 0-255]:" + port;
	   	   	   var waitForScan = 8000;
	   	   	   var goodFound = false;
	   	   	   
			   for(var cnt=0; cnt< 255; cnt++){
				  var machine = cnt.toString();
				 
				  var url = 'http://' + lan + machine + ':' + port;
				  this.get(url, function(goodurl, resp, timeout) {
					  
					  if(resp) {
					  	
					  	//This is a good server
						totalScanned ++;
									  
									  
						 //Save the first TODO: if more than one, open another screen here
						 localStorageSetItem("currentWifiServer", goodurl);
					 
						 clearInterval(scanning);
						 cb(goodurl, null);
						 goodFound = true;
					  } else {
					  	
						totalScanned ++;
						
						if(goodFound == false) {
							_this.notify("Scanning Wifi. Responses:" + totalScanned);
						}
					  	
					  }
					  
					  
				  });


			   }
		   }
	   }
	   

	   var pausing = false;
       //timeout check every 6 secs
       var scanning = setInterval(function() {
       		
       		
       		if(totalScanned < 255) {
       			//Let a user decide to continue
       			
       			if(pausing == false) {
       				pausing = true;		//Pausing prevents it from opening up more windows
					if(confirm("Timeout finding your Wifi server. Note: you have scanned for " + scanMessage + ", and received " + totalScanned + " responses. Do you wish to keep scanning?")) {
								//Yes, do nothing and wait.
								pausing = false;		//Can start asking again
						
					} else {
								//Exit out of here
								clearInterval(scanning);  
								cb(null, "Timeout finding your Wifi server.</br></br><a href='javascript:' onclick=\"app.enterServerManually('We scanned for " + scanMessage + ", and received " + totalScanned + " responses, but found no servers. You can enter this manually below:');\">More Details</a>");
					}
				}
	
			} else {	//Total scanned is complete
				//Have scanned the full range, error out of here.   
				clearInterval(scanning);     		 		
				cb(null, "We couldn't see your Wifi server.</br></br><a href='javascript:' onclick=\"app.enterServerManually('We scanned for " + scanMessage + ", and received " + totalScanned + " responses, but found no servers. You can enter this manually below:');\">More Details</a>");
			}
            
           
       }, waitForScan);

		

      } else {
		  //No lan detected
		  		  
         cb(null,"Local Wifi not detected. Note: If this app is streamed directly from medimage.co.nz, local 'direct Wifi' will not be available.<br/><br/><a href='javascript:' onclick=\"app.enterServerManually('Sorry, we could not detect the LAN. You can either install a local MedImage app server on the LAN, or you can enter the server address manually below:');\">More Details</a>");
         
        
      }
    },


    notify: function(msg) {
        //Set the user message
        document.getElementById("notify").innerHTML = msg;
    },
    
    cancelNotify: function(msg) {
        //Set the user message
        document.getElementById("cancel-trans").innerHTML = msg;
    },

	stopConnecting: function(cancelId) {
		//Similar to cancelUpload, but before the upload has started
		glbThis.continueConnectAttempts = false;
		
		
		if(glbThis.idbSupported == true) {
			var tx = glbThis.medImageSendCacheDb.transaction("images", "readwrite");
			var store = tx.objectStore("images");
			
			var photoCountRequest =  store.count();
			
			photoCountRequest.onsuccess = function() {
	  			//Set global
	  			checkConnected = photoCountRequest.result;
			}
		}
		
       	 
		
		
		//remove the photo from memory
		clearInterval(glbThis.cntLoopA);
		clearInterval(glbThis.cntLoopB);
		
		glbThis.notify("We have stopped trying to connect, but the photo has been stored. <a style=\"color:#f7afbb; text-decoration: none;\" href=\"javascript:\" onclick=\"app.loopLocalPhotosData(); return false;\">Retry</a><br/><br/><a style=\"color:#f7afbb; text-decoration: none;\" href=\"javascript:\" onclick=\"app.askForgetAllPhotos(); return false;\">Forget</a>");
		glbThis.cancelNotify("");			
		
	},

	cancelUpload: function(cancelId) {
		//Cancel during an upload
		
		var ft = fileTransferMap.getItem(cancelId);
		if (ft)
		{
			//Abort the upload. Cancel the Query.AJAX upload object 
		    ft.abort();
		    
		    //remove the photo
		    glbThis.changeLocalPhotoStatus(cancelId, "cancel");
		}		
		
	},
	
	
	determineFilenameData: function(idEntered, cb) {
		//Determines the filename to use based on the id entered of the photo 
		//and the id entered into the text field.
		//Calls back with: cb(err, newFilename)
		//    where err is null for no error, or text of the error,
		//    and the newFilename as a text string which includes the .jpg at the end
		//It will use the current date / time from the phone, thought this format varies slightly
		//phone to phone.

		//Have connected OK to a server
		var idEnteredB = idEntered;
		
 				
				
		var tempName = idEnteredB;
		if((tempName == '')||(tempName == null)) {
			tempName = 'image';
		}
		
		var initialHash = localStorageGetItem("initialHash");
		if((initialHash)&&(initialHash != null)) {
			if(initialHash == "true") {
				//Prepend the initial hash
				tempName = "#" + tempName;
			
			}
		} else {
			//Not set, so prepend the initial hash by default
			tempName = "#" + tempName;
		}

		var defaultDir = localStorageGetItem("defaultDir");
		if((defaultDir)&&(defaultDir != null)) {
			//A hash code signifies a directory to write to
			tempName = "#" + defaultDir + " " + tempName;
		} else {
			//In this case we have a blank defaultDir, which doesn't happen all that often. Double check we 
			//are actually using a remote server (not using a Wifi server)
		    alert("Warning: some app data has been forgotten. We will try to recover.");
			var foundWifiServer = null;
		   
	   		foundWifiServer = localStorageGetItem("currentWifiServer");
	   
			if((foundWifiServer)&&(foundWifiServer != null)&&(foundWifiServer != "")) {
					//Found a wifi server
					//Do nothing here
					
			} else {
				//Using a remote server - suggest re-pairing
				localStorageSetItem("newServer", "true");
				glbThis.bigButton();
				cb("Sorry, please pair again.");
				return;
			}


		}

		var myoutFile = tempName.replace(/ /g,'-');
		var idEnteredC = idEnteredB;				//Get a 2nd tier of variable
		
		

		//Get a current date/time
		var today = new Date();
		var dd = String(today.getDate()).padStart(2, '0');
		
		var mmConvert = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
		var mmm = mmConvert[today.getMonth()];
		var yyyy = today.getFullYear();

		var seconds = String(today.getSeconds()).padStart(2, '0');
		var hours = String(today.getHours()).padStart(2, '0');
		var minutes = String(today.getMinutes()).padStart(2, '0');

		mydt = dd + "-" + mmm + '-' + yyyy + '-' + hours + "-" + minutes + "-" + seconds;
		var myNewFileName = myoutFile + '-' + mydt + '.jpg';	
		cb(null, myNewFileName);
	
	},
	
	

	
	/**
	 * Convert a base64 string in a Blob according to the data and contentType.
	 * 
	 * @param b64Data {String} Pure base64 string without contentType
	 * @param contentType {String} the content type of the file i.e (image/jpeg - image/png - text/plain)
	 * @param sliceSize {Int} SliceSize to process the byteCharacters
	 * @see http://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript
	 * @return Blob
	 */
	b64toBlob: function(b64Data, contentType, sliceSize) {
        contentType = contentType || '';
        sliceSize = sliceSize || 512;

        var byteCharacters = atob(b64Data);
        var byteArrays = [];

        for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
            var slice = byteCharacters.slice(offset, offset + sliceSize);

            var byteNumbers = new Array(slice.length);
            for (var i = 0; i < slice.length; i++) {
                byteNumbers[i] = slice.charCodeAt(i);
            }

            var byteArray = new Uint8Array(byteNumbers);

            byteArrays.push(byteArray);
        }

		  var blob = new Blob(byteArrays, {type: contentType});
		  return blob;
	},

	
	
	uploadPhotoData: function(imageId, imageLocalFileIn, idEntered, newFilename) {
  
        var _this = this;
        
        
        if(!imageLocalFileIn) {
        	//No image data - just return a fail
        	var result = {};
			result.responseCode = 400;
			var textStatus = "error";
			result.statusText = "Sorry there was no image to send. Please try again.";
        	glbThis.fail(result, textStatus, imageId);
        	return;
        }
	
		var usingServer = localStorageGetItem("usingServer");
		
		var idEnteredB = idEntered;
	
	
		if((!usingServer)||(usingServer == null)||(usingServer == "")) {
			//No remote server already connected to, find the server now. And then call upload again
			_this.findServer(function(err) {
				var thisScope = {};
				thisScope.imageId = imageId;
				thisScope.imageLocalFileIn = imageLocalFileIn;
				thisScope.idEnteredB = idEnteredB;
				thisScope.newFilename = newFilename;
				
				
				
				if(err) {
					window.plugins.insomnia.allowSleepAgain();		//Allow sleeping again
					
					glbThis.notify("Sorry, we cannot connect to the server. Trying again in 10 seconds.");
					glbThis.cancelNotify("<ons-icon style=\"vertical-align: middle; color:#f7afbb;\" size=\"30px\" icon=\"fa-close\" href=\"#javascript\" onclick=\"app.stopConnecting('" + imageId + "');\"></ons-icon><br/>Cancel");
					//Search again in 10 seconds:
					
					
					//Countdown
					var cntDown = 10;
					glbThis.cntLoopA = setInterval(function() {
						cntDown --;
						if(cntDown <= 0) {
								clearInterval(glbThis.cntLoopA);				
						}
						if((cntDown >= 0) && (glbThis.continueConnectAttempts == true)) {
							glbThis.notify("Sorry, we cannot connect to the server. Trying again in " + cntDown + " seconds.");
						}
					},1000);
					
					glbThis.continueConnectAttempts = true;
					setTimeout(function() {
						if(glbThis.continueConnectAttempts == true) {
							glbThis.notify("Trying to connect again.");
							glbThis.uploadPhotoData(thisScope.imageId, thisScope.imageLocalFileIn, thisScope.idEnteredB, thisScope.newFilename);
						}
					}, 10000);
				} else {
					//Now we are connected, upload the photo again. But with the new connection, we need to know the full filename 
					_this.determineFilenameData(idEntered, function(err, newFilename) {   
						if(err) {
							//There was a problem getting the filename from the disk file
							glbThis.notify("Sorry, we cannot process the filename of the photo " + idEntered + ". If this happens consistently, please report the problem to medimage.co.nz");
	   
					   	} else {
							glbThis.uploadPhotoData(thisScope.imageId, imageLocalFileIn, idEnteredB, newFilename);
						}
						return;
					});
				}
			});
			return;
		} else {
			//Have connected OK to a server		
			
			var myImageLocalFileIn = imageLocalFileIn;
			var imageLocalFile = imageLocalFileIn;

			var options = new FileUploadOptions();
			options.fileKey="file1";
			options.mimeType="image/jpeg";

			var params = new Object();
			params.title = idEntered; 
			if((params.title == '')||(params.title == null)) {
				if((idEnteredB == '')||(idEnteredB == null)) {
					params.title = 'image';
				} else {
					params.title = idEnteredB;
				}
				
			}

			if((!usingServer)||(newFilename == null)||(newFilename == "")) {
				//We don't know the final filename. We likely recorded this entry when there was no connection. But now we definitely have a current connection.
				_this.determineFilenameData(idEntered, function(err, newFilename) { 
						if(err) {
							//There was a problem getting the filename from the disk file
							glbThis.notify("Sorry, we cannot process the filename of the photo " + idEntered + ". If this happens consistently, please report the problem to medimage.co.nz");
	   
					   	} else {
					   		//Loop back around again, with the filename
					   		glbThis.uploadPhotoData(imageId, imageLocalFileIn, idEntered, newFilename);
						}
						return;
				});			
			}

			options.fileName = newFilename;
			options.params = params;
			options.chunkedMode = false;		//chunkedMode = false does work, but still having some issues. =true may only work on newer systems?
			options.headers = {
				Connection: "close"
			}
			
			options.idEntered = idEnteredB;

			_this.notify("Uploading " + params.title);
			var serverReq = usingServer + '/api/photo';
			
			// Get the form element without jQuery
			var form = document.createElement("form");
			form.setAttribute("id", "photo-sending-frm-" + imageId);
			
			var imageData = imageLocalFileIn;	
			// Split the base64 string in data and contentType
			var block = imageData.split(";");
			// Get the content type of the image
			var contentType = block[0].split(":")[1];// In this case "image/gif"
			// get the real base64 content of the file
			var realData = block[1].split(",")[1];// In this case "R0lGODlhPQBEAPeoAJosM...."

			// Convert it to a blob to upload
			var blob = _this.b64toBlob(realData, contentType);

			// Create a FormData and append the file with "image" as parameter name
			var formDataToUpload = new FormData(form);
			

			formDataToUpload.append("file1", blob, newFilename);		//Note: "file1" is required by the MedImage Server.
			
			_this.cancelNotify("<ons-icon style=\"vertical-align: middle; color:#f7afbb;\" size=\"30px\" icon=\"fa-close\" href=\"#javascript\" onclick=\"app.cancelUpload('" + imageId + "');\"></ons-icon><br/>Cancel");
			
			var repeatIfNeeded = {
				"imageId" : imageId,
				"imageData" : imageLocalFileIn,
				"serverReq" : serverReq,
				"options" :options,
				"failureCount": 0,
				"nextAttemptSec": 15
			};		//TODO: confirm this is working correctly. We had removed the imageData, but I think it is still needed
			//as it is a RAM-based store, so it is back in.
			
			
			retryIfNeeded.push(repeatIfNeeded);
			
			
			//Keep the screen awake as we upload
			window.plugins.insomnia.keepAwake();
			
			
			var ft = jQuery.ajax({
				url: serverReq,
				data: formDataToUpload,// Add as Data the Previously create formData
				method:"POST",
				contentType:false,
				processData:false,
				cache:false,
				crossDomain: true,
				global: false,
				xhr: function () {
					var xhr = jQuery.ajaxSettings.xhr();
					xhr.upload.onprogress = glbThis.progress;
					return xhr;
				},
				error: function(err, textStatus) {
					console.error(err);
					var result = err;
					result.responseCode = 400;
					
					glbThis.fail(result, textStatus, imageId);
					form.remove();		//Clear up the DOM interface entry
				},
				success: function(data) {
					console.log(data);
					var result = {};
					
					result.responseCode = 200;	
					glbThis.win(result, imageId);
					form.remove();		//Clear up the DOM interface entry
					
				},
				complete:function(){

					console.log("Request finished.");
				}
			});
			
			fileTransferMap.setItem(imageId, ft);		//Make sure we can abort this photo later
			
			
			
			

	     
         }		//End of connected to a server OK
    },
    
    
   

   base64toBlob: function(b64Data, contentType, sliceSize) {
      var blob, byteArray, byteArrays, byteCharacters, byteNumbers, i, offset, slice;
      contentType = contentType || '';
      sliceSize = sliceSize || 512;
      byteCharacters = atob(b64Data);
      byteArrays = [];
      offset = 0;
      while (offset < byteCharacters.length) {
        slice = byteCharacters.slice(offset, offset + sliceSize);
        byteNumbers = new Array(slice.length);
        i = 0;
        while (i < slice.length) {
          byteNumbers[i] = slice.charCodeAt(i);
          i++;
        }
        byteArray = new Uint8Array(byteNumbers);
        byteArrays.push(byteArray);
        offset += sliceSize;
      }
      blob = new Blob(byteArrays, { type: contentType });
      return blob;
    },
    
    
    writeFile: function(fileEntry, base64, cb) {

	   
	   var _this = this;
	   
	   
	   fileEntry.createWriter(function(fileWriter) {
		 var data, string, type;
		 string = base64.split(';base64,');
		 type = string[0].split(':')[1];
		 data = _this.base64toBlob(string[1], type);
		 
		 fileWriter.onwriteend = function() {
		   console.log('Successful file write...');
		   
		   // Call function that would upload file via File Transfer plugin.
		   // Example: upload(fileEntry)
		   cb(fileEntry);
		 };

		 fileWriter.onerror = function(e) {
		   return console.log('Failed file write: ' + e.toString());
		 };
		 
		 return fileWriter.write(data);
	   });
	},
 

	
	

	
    progress: function(progressEvent) {
    	var statusDom = document.querySelector('#status');
    	
		if (progressEvent.lengthComputable) {
			var perc = Math.floor(progressEvent.loaded / progressEvent.total * 100);
			statusDom.innerHTML = perc + "% uploaded...";
		} else {
			if(statusDom.innerHTML == "") {
				statusDom.innerHTML = "Uploading";
			} else {
				statusDom.innerHTML += ".";
			}
		}
	},
	
	
	upload: function(repeatIfNeeded) {
	
		/* Structure:
			var repeatIfNeeded = {
				"imageId" : imageId,
				"imageData" : imageLocalFileIn,
				"serverReq" : serverReq,
				"options" :options,
				"failureCount": 0,
				"nextAttemptSec": 15
			};		
			
		*/
		var serverReq = repeatIfNeeded.serverReq;
		var imageId = repeatIfNeeded.imageId;
		var title = repeatIfNeeded.options.params.title; 
		var newFilename = repeatIfNeeded.options.fileName; 
		
		// Get the form element without jQuery
		var form = document.createElement("form");
		form.setAttribute("id", "photo-sending-frm-" + imageId);
		
		var imageData = repeatIfNeeded.imageData;	
		// Split the base64 string in data and contentType
		var block = imageData.split(";");
		// Get the content type of the image
		var contentType = block[0].split(":")[1];// In this case "image/gif"
		// get the real base64 content of the file
		var realData = block[1].split(",")[1];// In this case "R0lGODlhPQBEAPeoAJosM...."

		// Convert it to a blob to upload
		var blob = glbThis.b64toBlob(realData, contentType);

		// Create a FormData and append the file with "image" as parameter name
		var formDataToUpload = new FormData(form);
		

		formDataToUpload.append("file1", blob, newFilename);		//Note: "file1" is required by the MedImage Server.
			
		glbThis.notify("Uploading " + title);
	
		
		
		
		
		
	
		var ft = jQuery.ajax({
			url: serverReq,
			data: formDataToUpload,// Add as Data the Previously create formData
			type:"POST",
			contentType:false,
			processData:false,
			cache:false,
			xhr: function () {
				var xhr = jQuery.ajaxSettings.xhr();
				xhr.upload.onprogress = glbThis.progress;
				return xhr;
			},
			error: function(err, textStatus) {
				console.error(err);
				var result = err;
				result.responseCode = 400;
				glbThis.fail(result, textStatus, imageId);
				form.remove();		//Clear up
			},
			success: function(data) {
				console.log(data);
				var result = {};
				result.responseCode = 200;
				glbThis.win(result, imageId);
				form.remove();		//Clear up
				
			},
			complete:function(){

				console.log("Request finished.");
			}
		});
		
		repeatIfNeeded.ft = ft;
	
	},
	
			
    retry: function(existingText) {
    	    
    	    window.plugins.insomnia.allowSleepAgain();		//Allow sleeping again
    	    
	     	var repeatIfNeeded = retryIfNeeded.pop();
	     	
	     	if(repeatIfNeeded) {
	    	 	//Resend within a minute here
	    	 	var t = new Date();
				t.setSeconds(t.getSeconds() + repeatIfNeeded.nextAttemptSec);
				var timein = (repeatIfNeeded.nextAttemptSec*1000);		//In microseconds
	    	 	repeatIfNeeded.nextAttemptSec *= 3;						//Increase the delay between attempts each time to save battery
	    	 	if(repeatIfNeeded.nextAttemptSec > 21600) repeatIfNeeded.nextAttemptSec = 21600;		//If longer than 6 hours gap, make 6 hours (that is 60x60x6)
	    	 	var hrMin =  t.getHours() + ":" + t.getMinutes();
	    	 	
	    	 	glbThis.notify(existingText + " Retrying " + repeatIfNeeded.options.params.title + " at " + hrMin);
	    	
	    		repeatIfNeeded.failureCount += 1;						//Increase this
	    		if(repeatIfNeeded.failureCount > 2) {
	    			//Have tried too many attempts - try to reconnect completely (i.e. go
	    			//from wifi to network and vica versa
	    			localStorageRemoveItem("usingServer");				//This will force a reconnection
	    			localStorageRemoveItem("defaultDir");
	    			localStorageRemoveItem("serverRemote");
	    			glbThis.uploadPhotoData(repeatIfNeeded.imageId, repeatIfNeeded.options.idEntered, repeatIfNeeded.options.idEntered, repeatIfNeeded.options.fileName);
	    			
	    			//Clear any existing timeouts
	    			if(repeatIfNeeded.retryTimeout) {
	    				clearTimeout(repeatIfNeeded.retryTimeout);
	    			}
	    			
	    			//Clear the current transfer too i.e.
	    			//clear the AJAX call
	    			repeatIfNeeded.ft.abort();
	    			return;
	    		} else {
	    			//OK in the first few attempts - keep the current connection and try again
	    			//Wait 10 seconds+ here before trying the next upload					
					repeatIfNeeded.retryTimeout = setTimeout(function() {
					
						glbThis.notify("Trying to upload " + repeatIfNeeded.options.params.title);	
						glbThis.cancelNotify("<ons-icon size=\"30px\" style=\"vertical-align: middle; color:#f7afbb;\" icon=\"fa-close\" href=\"#javascript\" onclick=\"app.cancelUpload('" + repeatIfNeeded.imageId + "');\"></ons-icon><br/>Cancel");
					
						retryIfNeeded.push(repeatIfNeeded);
					
						//Keep the screen awake as we upload
						window.plugins.insomnia.keepAwake();
						var myImageId = repeatIfNeeded.imageId;
						
						//Carry out the upload
						glbThis.upload(repeatIfNeeded);
						
						
					}, timein);											//Wait 10 seconds before trying again	
				}
	     	}
      },



	  removeCheckComplete: function(imageId) {
			//Loop through the current array and remove the entries
	
			for(var cnt = 0; cnt< checkComplete.length; cnt++) {
				if(checkComplete[cnt].details && checkComplete[cnt].details.imageId && checkComplete[cnt].details.imageId === imageId) {
						checkComplete[cnt] = null;		//Need the delete first to get rid of subobjects
				}
			}
	
			 //Remove the null array entries
			 checkComplete = glbThis.arrayRemoveNulls(checkComplete);
			 return;
	
	  },
	
	  removeRetryIfNeeded: function(imageId) {
			//Loop through the current array and remove the entries
	
			for(var cnt = 0; cnt< retryIfNeeded.length; cnt++) {
				if(retryIfNeeded[cnt].imageId === imageId) {
						retryIfNeeded[cnt] = null;		//Need the delete first to get rid of subobjects
				}
			}
	
			 //Remove the null array entries
			 retryIfNeeded = glbThis.arrayRemoveNulls(retryIfNeeded);
			 return;
	
	  },

	  check: function(imageId){
	  		//Checks to see if the next photo on the server (in the checkComplete stack) has been sent on to the PC successfully. If not it will keep pinging until is has been dealt with, or it times out.
	  		
		  	var startSlowLoop = false;
	  		var nowChecking = null;
	  		for(var cnt = 0; cnt < checkComplete.length; cnt++) {
	  			if(checkComplete[cnt].details.imageId === imageId) {
	  				nowChecking = JSON.parse(JSON.stringify(checkComplete[cnt]));
					checkComplete[cnt].loopCnt --;		//Decrement the original
					if(nowChecking.loopCnt <= 0) {
						//Now continue to check with this photo, but only once every 30 seconds, 100 times (i.e. about 45 minutes).
						if(!nowChecking.slowLoopCnt) {
							//Need to set a slow count
							checkComplete[cnt].slowLoopCnt = 100;
							startSlowLoop = true;
						} else {
							//Decrement the slow loop
							checkComplete[cnt].slowLoopCnt --;						
						}
					}
	  			}
	  		}
	  		if(!nowChecking) {
	  			//This check is complete, already. Strictly speaking we shouldn't get here unless we've been deleted
	  								
	  			return;
	  		}
			nowChecking.loopCnt --;
			
		 
			if(nowChecking.loopCnt <= 0) {
				
				
 				//Have finished - remove interval and report back
				if(startSlowLoop == true) {
					//Have now finished the frequent checks. Move into slower checks.
					
					
					var myTitle = "Image";
					if(nowChecking.details && nowChecking.details.options && nowChecking.details.options.params && nowChecking.details.options.params.title && nowChecking.details.options.params.title != "") {
						myTitle = nowChecking.details.options.params.title;
					}
				
					document.getElementById("notify").innerHTML = "You are experiencing a slightly longer transfer time than normal.  Your image " + myTitle + " should be delivered shortly, and you can carry on taking new photos, but you won't be notified of delivery. You can also <a style=\"color:#f7afbb; text-decoration: none;\" href=\"javascript:\" onclick=\"app.askForgetAllPhotos(); return false;\">forget</a> them fully.";
					
					window.plugins.insomnia.allowSleepAgain();			//Allow the screen to sleep, we could be here for a while.
					
					
					
					
					//The file exists on the server still - try again in 30 seconds
					var thisScope = {};
					thisScope.imageId = imageId;
					setTimeout(function() {
						glbThis.check(thisScope.imageId);						
					}, 30000);
				} else {
					//Count down inside the slower checks
					nowChecking.slowLoopCnt --;
					
					
					if(nowChecking.slowLoopCnt <= 0) {
						//Have finished the long count down, and given up
						document.getElementById("notify").innerHTML = "Sorry, the image is on the remote server, but has not been delivered to your local PC.  We will try again once your app restarts. <a style=\"color:#f7afbb; text-decoration: none;\" href=\"javascript:\" onclick=\"app.askForgetAllPhotos(); return false;\">Forget</a>";
						
						glbThis.cancelNotify("");		//Remove any cancel icons
					} else {
						//Otherwise in the long count down
						var myNowChecking = nowChecking;
						
						
						glbThis.get(nowChecking.fullGet, function(url, resp) {
					
					
							if((resp === "false")||(resp === false)) {
								//File no longer exists, success!
								
								glbThis.cancelNotify("");		//Remove any transfer icons
								var myTitle = "Image";
								if(myNowChecking.details && myNowChecking.details.options && myNowChecking.details.options.params && myNowChecking.details.options.params.title && myNowChecking.details.options.params.title != "") {
									myTitle = myNowChecking.details.options.params.title;
								}
								if(myTitle === "image") myTitle = "Image";
								
								glbThis.removeCheckComplete(myNowChecking.details.imageId);
								
								var moreLength = (checkComplete.length + retryIfNeeded.length) - 1;
								var more = " <a style=\"color:#f7afbb; text-decoration: none;\" href=\"javascript:\" onclick=\"app.askForgetAllPhotos(); return false;\">" + moreLength + " more</a>";	
  								
  								if(moreLength >= 0) {
									if(moreLength == 0) {
										document.getElementById("notify").innerHTML = myTitle + ' transferred. Success! ';								
									
									} else {
									
										if(myTitle != "") {
									
											document.getElementById("notify").innerHTML = myTitle + ' transferred. Success!' + more;
										} else {
											document.getElementById("notify").innerHTML = 'Image transferred. Success!' + more;
										}
									}
								} else {
									return;
								}
								
								
								//and delete phone version
								if(myNowChecking.details) {
									glbThis.changeLocalPhotoStatus(myNowChecking.details.imageId, 'cancel');
								} else {
									document.getElementById("notify").innerHTML = 'Image transferred. Success! ' + more + ' Note: The image will be resent on a restart to verify.';
								}
							} else {
								//The file exists on the server still - try again in 30 seconds
								var myTitle = "Image";
								if(myNowChecking.details && myNowChecking.details.options && myNowChecking.details.options.params && myNowChecking.details.options.params.title && myNowChecking.details.options.params.title != "") {
									myTitle = myNowChecking.details.options.params.title;
								}
								if(myTitle === "image") myTitle = "Image";
								
								var moreLength = (checkComplete.length + retryIfNeeded.length);
								var more = " <a style=\"color:#f7afbb; text-decoration: none;\" href=\"javascript:\" onclick=\"app.askForgetAllPhotos(); return false;\">" + moreLength + " more</a>";	
            		
								if(!nowChecking.slowLoopCnt) {
									nowChecking.slowLoopCnt = 100;	//Init								
								}
								if(moreLength >= 0) {
									if(moreLength == 0) {
										document.getElementById("notify").innerHTML = myTitle + ' has not finished transferring. Checking again in 30 seconds. ' + myNowChecking.slowLoopCnt;								
									
									} else {
									
										if(myTitle != "") {
									
											document.getElementById("notify").innerHTML = myTitle + ' has not finished transferring. Checking again in 30 seconds.' + more + ' ' + myNowChecking.slowLoopCnt;
										} else {
											document.getElementById("notify").innerHTML = 'Image transferred. Success!' + more + myNowChecking.slowLoopCnt;
										}
									}
								} else {
									return;
								}
								
								
								var thisScope = {};
								if(myNowChecking && myNowChecking.details) {
									thisScope.imageId = myNowChecking.details.imageId;
							
								
									setTimeout(function() {
										glbThis.check(thisScope.imageId);
									}, 30000);
								}
							} 
						});
					}
				}
 
 
			} else {
				//Try a get request to the check
				//Get the current file data
				
				glbThis.cancelNotify("");		//Remove any cancel icons
				var myNowChecking = nowChecking;
				
				var myTitle = "Image";
				if(myNowChecking.details && myNowChecking.details.options && myNowChecking.details.options.params && myNowChecking.details.options.params.title && myNowChecking.details.options.params.title != "") {
							myTitle = myNowChecking.details.options.params.title;
				}
				if(myTitle === "image") myTitle = "Image";
				var moreLength = (checkComplete.length + retryIfNeeded.length) - 1;	//The -1 is to not include the current in the count
				var more = " <a style=\"color:#f7afbb; text-decoration: none;\" href=\"javascript:\" onclick=\"app.askForgetAllPhotos(); return false;\">" + moreLength + " more</a>";	
 				if(moreLength >= 0) {
					if(moreLength == 0) {
						document.getElementById("notify").innerHTML = myTitle + ' on server. Transferring to PC..';
					} else {
						if(myTitle != "") {
							document.getElementById("notify").innerHTML = myTitle + ' on server. Transferring to PC..' + more;
				
						} else {
							document.getElementById("notify").innerHTML = 'Image on server. Transferring to PC..' + more;
						}
					}
				
					glbThis.cancelNotify("<ons-icon style=\"vertical-align: middle; color:#DDD;\" size=\"20px\" spin icon=\"fa-spinner\"></ons-icon><br/>");
				} else {
					return;
				}
				
  
  
  				var myNowChecking = nowChecking;
				glbThis.get(nowChecking.fullGet, function(url, resp) {
					
					if((resp === "false")||(resp === false)) {
						//File no longer exists, success!
						glbThis.cancelNotify("");		//Remove any transfer icons
						
						glbThis.removeCheckComplete(myNowChecking.details.imageId);
						
						var myTitle = "Image";
						if(myNowChecking.details && myNowChecking.details.options && myNowChecking.details.options.params && myNowChecking.details.options.params.title && myNowChecking.details.options.params.title != "") {
							myTitle = myNowChecking.details.options.params.title;
						}
						if(myTitle === "image") myTitle = "Image";
						
						
						var moreLength = (checkComplete.length + retryIfNeeded.length);
						var more = " <a style=\"color:#f7afbb; text-decoration: none;\" href=\"javascript:\" onclick=\"app.askForgetAllPhotos(); return false;\">" + moreLength + " more</a>";	
            			if(moreLength >= 0) {
							if(moreLength == 0) {
								document.getElementById("notify").innerHTML = myTitle + ' transferred. Success!'; 
							} else {
								if(myTitle != "") {
									document.getElementById("notify").innerHTML = myTitle + ' transferred. Success!' + more;
								} else {
									document.getElementById("notify").innerHTML = 'Image transferred. Success!' + more;
								}
							}
						} else {
							return;
						}
						
						
						
						
						
						//and delete phone version
						if(myNowChecking.details) {
            						glbThis.changeLocalPhotoStatus(myNowChecking.details.imageId, 'cancel');
            					} else {
            						document.getElementById("notify").innerHTML = 'Image transferred. Success!' + more + ' Note: The image will be resent on a restart to verify.';
            					}
						
					} else {
						//The file exists on the server still - try again in a few moments
						var thisScope = {};
						if(myNowChecking && myNowChecking.details) {
							thisScope.imageId = myNowChecking.details.imageId;
						
							setTimeout(function() {
								glbThis.check(thisScope.imageId);
							}, 2000);
						}
					} 
				});
			}
									
								
	},
						

    win: function(r, imageId) {
    	    
	    
    	    //Have finished transferring the file to the server
    	    window.plugins.insomnia.allowSleepAgain();		//Allow sleeping again
    	    
    	    document.querySelector('#status').innerHTML = "";	//Clear progress status
    	    
    	   
    	    glbThis.cancelNotify("");		//Remove any cancel icons
 
 
    	    //Check if this was a transfer to the remote server
            console.log("Code = " + r.responseCode);
            //console.log("Response = " + r.response);
            //console.log("Sent = " + r.bytesSent);
            if((r.responseCode == 200)||((r.response) && (r.response.indexOf("200") != -1))) {
            
            	var remoteServer = localStorageGetItem("serverRemote");
            	if(remoteServer == 'false') {
            		//i.e. Wifi case
            		
            		
            		glbThis.cancelNotify("");		//Remove any transfer icons
            		
            		//and delete phone version of file
					var repeatIfNeeded = null;
					for(var cnt=0; cnt< retryIfNeeded.length; cnt++) {
						if(retryIfNeeded[cnt].imageId === imageId) {
							repeatIfNeeded =  JSON.parse(JSON.stringify(retryIfNeeded[cnt]));
						}
					}	
            		            		
            																	
            		var moreLength = (checkComplete.length + retryIfNeeded.length) - 1;
            		if(moreLength >= 0) {
						if(moreLength == 0) {
							var more = "";
						} else {
							var more = " <a style=\"color:#f7afbb; text-decoration: none;\" href=\"javascript:\" onclick=\"app.askForgetAllPhotos(); return false;\">" + moreLength + " more</a>";	
						}
					} else {
						return;
					}
            		var myTitle = "Image";
            		
            		if(repeatIfNeeded) {
        
						glbThis.removeRetryIfNeeded(repeatIfNeeded.imageId);		
            			
            			
						if(repeatIfNeeded && repeatIfNeeded.options && repeatIfNeeded.options.params && repeatIfNeeded.options.params.title && repeatIfNeeded.options.params.title != "") {
							myTitle = repeatIfNeeded.options.params.title;
							if(myTitle === "image") myTitle = "Image";
							document.getElementById("notify").innerHTML = myTitle + ' transferred. Success!' + more;
							
							
						} else {
							document.getElementById("notify").innerHTML = 'Image transferred. Success!' + more;
						}
            		
            			glbThis.changeLocalPhotoStatus(repeatIfNeeded.imageId, 'cancel');
            		} else {
						//Trying to check, but no file on stack	
						document.getElementById("notify").innerHTML = 'Image transferred. Success!' + more + ' Note: The image will be resent on a restart to verify.';
					}
            
            	} else {
            		//Onto remote server - now do some pings to check we have got to the PC
            		//and delete phone version of file
					var repeatIfNeeded = null;
					for(var cnt=0; cnt< retryIfNeeded.length; cnt++) {
						if(retryIfNeeded[cnt].imageId === imageId) {
							repeatIfNeeded =  JSON.parse(JSON.stringify(retryIfNeeded[cnt]));
						}
					}	
					
					var moreLength = (checkComplete.length + retryIfNeeded.length) - 1;		    		
				    var more = " <a style=\"color:#f7afbb; text-decoration: none;\" href=\"javascript:\" onclick=\"app.askForgetAllPhotos(); return false;\">" + moreLength + " more</a>";	
            		
				    var myTitle = "Image";
					
					if(repeatIfNeeded && repeatIfNeeded.options && repeatIfNeeded.options.params && repeatIfNeeded.options.params.title && repeatIfNeeded.options.params.title != "") {
						myTitle = repeatIfNeeded.options.params.title;
					}
					if(myTitle === "image") myTitle = "Image";
					
					if(moreLength >= 0) {
						if(moreLength == 0) {
							document.getElementById("notify").innerHTML = myTitle + ' on server. Transferring to PC..';
						} else {
							if(myTitle != "") {
								document.getElementById("notify").innerHTML = myTitle + ' on server. Transferring to PC..' + more;
							} else {
								document.getElementById("notify").innerHTML = 'Image on server. Transferring to PC..' + more;
							}
						}
					
						glbThis.cancelNotify("<ons-icon style=\"vertical-align: middle; color:#DDD;\" size=\"20px\" spin icon=\"fa-spinner\"></ons-icon><br/>");
					} else {
						return;
					}
		
            		
			
			
            		
            		
	     			
	     	
					if(repeatIfNeeded) {
						var thisFile = repeatIfNeeded.options.fileName;
						var usingServer = localStorageGetItem("usingServer");
					
						if((usingServer)&&(usingServer != "")) {	//Note, we have had a case of a null server here. In this case
											//simply don't do any follow on checks.
							var fullGet = usingServer + '/check=' + encodeURIComponent(thisFile);
						
							var nowChecking = {};
					
							nowChecking.loopCnt = 11; //Max timeout = 11*2 = 22 secs but also a timeout of 5 seconds on the request.
							nowChecking.fullGet = fullGet;
							nowChecking.details = repeatIfNeeded;
							checkComplete.push(nowChecking);
					
							//Set an 'onserver' status
							glbThis.changeLocalPhotoStatus(repeatIfNeeded.imageId, 'onserver', nowChecking);
					
							var self = {};
							self.thisImageId = repeatIfNeeded.imageId;
							setTimeout(function() {	//Wait two seconds and then do a check
								glbThis.check(self.thisImageId);
							}, 2000);
					
							glbThis.removeRetryIfNeeded(repeatIfNeeded.imageId);		
					
						
						
						} else {
							//Set an 'onserver' status, and remove this entry
							glbThis.changeLocalPhotoStatus(repeatIfNeeded.imageId, 'onserver', nowChecking);
							glbThis.removeRetryIfNeeded(repeatIfNeeded.imageId);
						}
						
						
					} else {
						//Trying to check, but no file on stack	
					}
            	
            	}	//End of if(remoteServer == 'false')
            	            	
            	//Save the current server settings for future reuse
            	glbThis.saveServer();


            
            } else {
            	//Retry sending
            	glbThis.retry("");
            	
            }

    },


    fail: function(error, textStatus, imageId) {
  
  		window.plugins.insomnia.allowSleepAgain();			//Allow the screen to sleep
  		
  		document.querySelector('#status').innerHTML = "";	//Clear progress status
  
  		glbThis.cancelNotify("");		//Remove any cancel icons
  		

		if(error.statusText) {
			var errorMessage = error.statusText;
		} else {
			var errorMessage = "Please contact medimage.co.nz for assistance.";
		}
  		
  		
  		if(error.status == 503) {
  			//Server not available
  			glbThis.notify("Sorry you have tried to send it to an invalid URL.");
  		} else {
  		
		    switch(textStatus)
		    {
		        case "cancel":
		            glbThis.notify("The photo was uploaded.");
		            
		            //Remove the photo from the list
		            glbThis.changeLocalPhotoStatus(imageId, 'cancel');
		        break;

		        case "timeout":
		            glbThis.notify("Waiting for better reception..");
		            glbThis.retry("Waiting for better reception...</br>");
		        break;

		        case "abort":
		            glbThis.notify("Your image transfer was aborted. <a style=\"color:#f7afbb; text-decoration: none;\" href=\"javascript:\" onclick=\"app.askForgetAllPhotos(); return false;\">Remove Permanently</a>");
		            //No need to retry here: glbThis.retry("Sorry, your image transfer was aborted.</br>");
		             
		        break;

		        default:  		
		            glbThis.notify("An error has occurred: " + errorMessage);
		        break;
		    }
        }
    },
    
    
    forgetAllPhotos: function() {
    	//Loop through all photos in retryIfNeeded, checkComplete and localPhotos and remove them
    	//all.
    	 var _this = this;
    	 glbThis = this;
    	 
  		for(var cnta = 0; cnta < retryIfNeeded.length; cnta++) {
  			if(retryIfNeeded[cnta].imageId) {
  				_this.cancelUpload(retryIfNeeded[cnta].imageId);
  				_this.removeRetryIfNeeded(retryIfNeeded[cnta].imageId);
  			}
  		
  		}	
  		
  		for(var cntb = 0; cntb < checkComplete.length; cntb++) {
  			
  			if(checkComplete[cntb].details && checkComplete[cntb].details.imageId) {
  				_this.removeCheckComplete(checkComplete[cntb].details.imageId);
  			}
  		
  		}
  		
  		
  		//Go through storage and clear out each entry
   		if(glbThis.idbSupported == true) {
	  		var tx = glbThis.medImageSendCacheDb.transaction("images", "readwrite");
			var store = tx.objectStore("images");
			
			
			var request = tx.objectStore("images").openCursor();
		 	request.onsuccess = function(e) {   
			   var cursor = request.result || e.result;             
			   if(cursor && cursor.value){             
				     
				  
				  var newPhoto = cursor.value;
	  		      if(newPhoto.imageId) {
	  		      	_this.changeLocalPhotoStatus(newPhoto.imageId, 'cancel');
	  		      }
	  				
	  			}
	  		}
	  	}
   	
   		glbThis.notify("All photos have been deleted and forgotten.");
   		glbThis.cancelNotify("");		//Remove any cancel icons
    
    },
    
    askForgetAllPhotos: function() {
    	//Ask if we want to remove all the photos on the system
             		
    	//Get a live current photo count
    	var moreLength = checkComplete.length + retryIfNeeded.length + checkConnected;
    	if(moreLength == 1) {
    		var moreStr = "is " + moreLength + " photo";
    	} else {
    		var moreStr = "are " + moreLength + " photos";
    	}
    	
     	navigator.notification.confirm(
				'There ' + moreStr + ' in memory. Do you want to forget and delete all of these photos? (Some of them may have been sent already)',  // message
				function(buttonIndex) {
					if(buttonIndex == 1) {
						glbThis.forgetAllPhotos();
						return;
					} else {
						return;
					}
	
				},                  			// callback to invoke
				'Forget Photos',            	// title
				['Yes','No']             		// buttonLabels
			);
    },

    getip: function(cb) {

           var _this = glbThis;

           //timeout after 3 secs -rerun this.findServer()
           var iptime = setTimeout(function() {
                  var err = "You don't appear to be connected to your wifi. Please connect and try again.";
                  
                  cb(null, err);
           }, 5000);

           networkinterface.getWiFiIPAddress(function(ipInfo) {
           		
           		
           		if(ipInfo.ip) {
		            _this.ip = ipInfo.ip;			//note: we could use ipInfo.subnet here but, this could be a 16-bit subnet rather than 24-bit?
		            var len =  ipInfo.ip.lastIndexOf('\.') + 1;
		            _this.lan = ipInfo.ip.substr(0,len);
		            clearTimeout(iptime);
		            cb(null);
		        } else {
		        	//Could be an inet:6 version e.g 2404:4407:27f0:8100:a693:9810:7740:787. For now, just treat as 127.0.0.1. TODO: improve this
		        	_this.ip = "127.0.0.1";			
		        	var host = window.location.host; 
		       
		        	host = host.replace("https://", "");
		        	host = host.substring(0, host.indexOf(':'));		//Remove port
		        	_this.ip = host.replace("http://", "");
		        	
		        	var len =  _this.ip.lastIndexOf('\.') + 1;
		            if(len > 0) {
		            	_this.lan = _this.ip.substr(0,len);
		            } else {
		            	_this.lan = _this.ip;	//E.g. "localhost" or some other domain
		            }
		            clearTimeout(iptime);
		            cb(null);
		        	
		        }
           },
           function(err) {
           	   var retErr = "Sorry, there was a problem getting your IP address.<br/><br/><a href='javascript:' onclick=\"navigator.notification.alert('Error: " + err + "', function() {}, 'More Details');\">More Details</a>";
           	   cb(null, retErr);
           });
    },

    
    
    
    
    
    factoryReset: function() {
        //We have connected to a server OK
       
        var _this = this;
        
    		navigator.notification.confirm(
	    		'Are you sure? All your saved PCs and other settings will be cleared.',  // message
	    		function(buttonIndex) {
	    			if(buttonIndex == 1) {
						localStorageClear();
						
						localStorageRemoveItem("usingServer");							//Init it
						localStorageRemoveItem("defaultDir");							//Init it
						localStorageRemoveItem("currentRemoteServer");
	   					localStorageRemoveItem("currentWifiServer");
	   					
	   					localStorageRemoveItem("ce");									//And all the other options
	   					localStorageRemoveItem("rf");
	   					localStorageRemoveItem("serverOptions");
	   					localStorageRemoveItem("serverRemote");
	   					localStorageRemoveItem("settings");
	   					localStorageRemoveItem("tr");
	   					
	   					localStorageSetItem("initialHash", "true");					//Default to write a folder
						document.getElementById("always-create-folder").checked = true;
						
						
						//Now refresh the current server display
    					document.getElementById("currentPC").innerHTML = "";
    		
    					
    					alert("Cleared all saved PCs.");
    					
    					
    					//Check if we have existing photos
    					if(glbThis.idbSupported == true) {
      						
      						var imageIds = [];
      						
		  					var tx = glbThis.medImageSendCacheDb.transaction("images", "readwrite");
							var store = tx.objectStore("images");
							var request = tx.objectStore("images").openCursor();
						 	request.onsuccess = function(e) {   
							   var cursor = request.result || e.result;             
							   if(cursor && cursor.value){ 
							   	  //We have some existing photos
								  var newPhoto = cursor.value;
								  
								  
								  imageIds.push(newPhoto.imageId);
						  	   }
						  	}
						  	
						  	if(imageIds.length > 0) {
						 
								 navigator.notification.confirm(
									'Do you wish to clear the existing photos, also?',  // message
									function(buttonIndex) {
										if(buttonIndex == 1) {
											for(var cnt = 0; cnt< imageIds.length; cnt++) {
												glbThis.removeLocalPhoto(imageIds[cnt]);
											}
										}
									},                			 	// callback to invoke
									'Clear Photos',            	// title
									['Ok','Cancel']             	// buttonLabels
										
								); 	
						  	
						  	} 
						}
    					
						
								
		
						glbThis.openSettings();
						
					}	//End of btnindex = 1
	    		
	    		},                 			 	// callback to invoke
	    		'Clear Settings',            	// title
	    		['Ok','Cancel']             	// buttonLabels
			);
        
		return false;
    },
    

    checkDefaultDir: function(server) {
        //Check if the default server has a default dir eg. input:
        //   http://123.123.123.123:5566/write/fshoreihtskhfv
        //Where the defaultDir would be 'fshoreihtskhfv'
        //Returns '{ server: "http://123.123.123.123:5566", dir: "fshoreihtskhfv"'
        var requiredStr = "/write/";
        var startsAt = server.indexOf(requiredStr);
        if(startsAt >= 0) {
            //Get the default dir after the /write/ string
            var startFrom = startsAt + requiredStr.length;
            var defaultDir = server.substr(startFrom);
            var properServer = server.substr(0, startsAt);
            return { server: properServer, dir: defaultDir };
        } else {
            return { server: server, dir: "" };
        }

    },


	connect: function(results, photoData) {
		
    	//Save the server with a name
    	//Get existing settings array    	
    	switch(results.buttonIndex) {
    	
    		case 1:
    			//Clicked on 'Ok'
    			//Start the pairing process
    			var pairUrl = centralPairingUrl + '?compare=' + results.input1;
			   		glbThis.notify("Pairing..");
			   		glbThis.get(pairUrl, function(url, resp) {

						if(resp) {		
						   	resp = resp.replace('\n', '')

					   		if(resp == 'nomatch') {
								glbThis.notify("Sorry, there was no match for that code.");
								return;

					   		} else {

								
								var server = resp;
								
								glbThis.notify("Pairing success.");
								
								//And save this server
								localStorageSetItem("currentRemoteServer",server);
								localStorageRemoveItem("currentWifiServer");  				//Clear the wifi
								localStorageRemoveItem("usingServer");						//Init it
								localStorageRemoveItem("defaultDir");						//Init it


								  navigator.notification.confirm(
									'Do you want to connect via WiFi directly, if it is available, also?',  // message
									function(buttonIndex) {
										if(buttonIndex == 1) {
											//yes, we also want to connect via wifi
											glbThis.checkWifi(function(err) {
												if(err) {
													//An error finding wifi
													glbThis.notify(err);
													glbThis.bigButton();
													//Send off current 
												} else {
													//Ready to take a picture, rerun with this
													//wifi server
													glbThis.notify("WiFi paired successfully.");
													glbThis.bigButton();
												}
											});
										} else {
											glbThis.notify("Pairing success, without WiFi.");
											glbThis.bigButton();
										}
						
									},                  			// callback to invoke
									'Pairing Success!',            	// title
									['Yes','No']             		// buttonLabels
								);
								
			  
								return;
					   		}
					   	} else {
					   		//A 404 response
					   		glbThis.notify("Sorry, we could not connect to the pairing server. Please try again.");
					   	}

			   	}); //end of get
    			
    			return;
    		break;
    	
    		case 2:
    			//Clicked on 'Wifi only'
    			//Otherwise, first time we are running the app this session	
    			localStorageRemoveItem("currentWifiServer");  			//Clear the wifi
				localStorageRemoveItem("currentRemoteServer");  		//Clear the wifi
				localStorageRemoveItem("usingServer");					//Init it
				localStorageRemoveItem("defaultDir");					//Init it
				
				glbThis.checkWifi(function(err) {
					if(err) {
						//An error finding server - likely need to enter a pairing code. Warn the user
						glbThis.notify(err);
					} else {
						//Ready to take a picture, rerun
						glbThis.notify("Wifi paired successfully.");
						
						glbThis.bigButton();
					}
				});
				
				return;
    		break;
    		
    		default:
    			//Clicked on 'Cancel'
    		
    		break;
    	
		}
	},


    bigButton: function(photoData) {

        //Called when pushing the big button
        var _this = this;

		//Record this current photo immediately for future reference.
	   if(photoData) {
			currentPhotoData = photoData;
	   } else {
	   		if(currentPhotoData) {
	   			//Otherwise use the RAM stored version
	   			photoData = currentPhotoData;
	   		}   	
	   }
       var foundRemoteServer = null;
       var foundWifiServer = null;
       var newServer = null;
	   foundRemoteServer = localStorageGetItem("currentRemoteServer");
	   foundWifiServer = localStorageGetItem("currentWifiServer");
	   newServer = localStorageGetItem("newServer");

	   if((newServer)&&(newServer == "true")) {
	   		//Likely need to enter a pairing code. Warn the user
			//No current server - first time with this new connection

			//We have connected to a server OK
			navigator.notification.prompt(
				'Please enter the 4 letter pairing code from your PC.',  	// message
				glbThis.connect,                  						// callback to invoke
				'New Connection',            								// title
				['Ok','Use Wifi Only','Cancel'],             				// buttonLabels
				''                 											// defaultText
			);
	   
	   		localStorageSetItem("newServer", "false");				//Should only have registered as a new server one time.
	   } else {
			//Not a new server - but check if we have
			if(((foundRemoteServer == null)||(foundRemoteServer == ""))&&
		   		 ((foundWifiServer == null)||(foundWifiServer == ""))) {

				//There is a chance that our currentRemoteServer has simply been forgotten. Before asking for a pairing code,
				//see if we can't resurrect the data from the Settings
			
				var settings = this.getArrayLocalStorage("settings");
				if((settings)&&(settings[0])) {
					//There is some existing storage
					
					alert("Warning: the app has forgotten where it was sending photos, and has been switched to the default server '" + settings[0].name + "'");
					var currentRemoteServer = settings[0].currentRemoteServer;			
        			var currentWifiServer = settings[0].currentWifiServer;	
										
					localStorageRemoveItem("usingServer"); //reset the currently used server
       
					//Save the current server
					localStorageRemoveItem("defaultDir");
					
					//Remove if one of these doesn't exist, and use the other.
					if((!currentWifiServer)||(currentWifiServer == null)||(currentWifiServer =="")) {
						localStorageRemoveItem("currentWifiServer");
					} else {
						localStorageSetItem("currentWifiServer", currentWifiServer);
					}
					
					if((!currentRemoteServer)||(currentRemoteServer == null)||(currentRemoteServer == "")) {
						localStorageRemoveItem("currentRemoteServer");
					} else {
						localStorageSetItem("currentRemoteServer", currentRemoteServer);
					}
				
					//Set the name
        			localStorageSetItem("currentServerName", settings[0].name);
					
					//Now refresh the current server display
    				document.getElementById("currentPC").innerHTML = settings[0].name;
    				
    				//And now we are ready to try again
    				_this.bigButton(photoData);
    				return;
								
    				
				}
		    
				//Likely need to enter a pairing code. Warn the user
				//No current server - first time with this new connection

				//We have connected to a server OK
				navigator.notification.prompt(
					'Please enter the 4 letter pairing code from your PC.',  	// message
					glbThis.connect,                  						// callback to invoke
					'New Connection',            								// title
					['Ok','Use Wifi Only','Cancel'],             				// buttonLabels
					''                 											// defaultText
				);
			} else {
				//Yes, we have at least one current server
				//Process the picture
	    		app.processPictureData(photoData); 
           		app.takingPhoto = false;		//Have finished with the camera
           
			}
		}

    },


	checkWifi: function(cb) {
	    glbThis.notify("Checking Wifi connection");

       this.getip(function(ip, err) {

          if(err) {
             cb(err);
             return;
          }

          glbThis.notify("Scanning Wifi");

          glbThis.scanlan('5566', function(url, err) {

             if(err) {
               cb(err);
             } else {
               cb(null);
             }

          });
       });
	
	},

	
	getOptions: function(guid, cb) {
		//Input a server dir e.g. uPSE4UWHmJ8XqFUqvf
		//   where the last part is the guid.
		
		//Get a URL like this: https://medimage-pair.atomjump.com/med-settings.php?type=get&guid=uPSE4UWHmJ8XqFUqvf
		//to get a .json array of options.
		
		var settingsUrl = "https://medimage-pair.atomjump.com/med-settings.php?type=get&guid=" + guid;
		
		var myCb = cb;
		
		glbThis.get(settingsUrl, function(url, resp) {
			
			if(resp != "") {
				
				var options = JSON.stringify(resp);		//Or is it without the json parsing?
				
				if(options) {
					//Set local storage
					//localStorageRemoveItem("serverOptions");
					localStorageSetItem("serverOptions", options);
					myCb(null);
				} else {
					myCb("No options");
				}
			} else {
				myCb("No options");
			}
		});
	
	},
	
	clearOptions: function() {
		localStorageRemoveItem("serverOptions");
	},

    findServer: function(cb) {

	   //Check storage for any saved current servers, and set the remote and wifi servers
	   //along with splitting any subdirectories, ready for use by the the uploader.
	   //Then actually try to connect - if wifi is an option, use that first
       var _this = this;
              
       var alreadyReturned = false;
       var found = false;
       
       //Clear off
       var foundRemoteServer = null;
       var foundWifiServer = null;
       var foundRemoteDir = null;
       var foundWifiDir = null;
       var usingServer = null;
  
         
       this.clearOptions();
       
       //Early out
       usingServer = localStorageGetItem("usingServer");
       
       
       
       if((usingServer)&&(usingServer != null)&&(usingServer != "")) {
       		//We already have a known connected server, return without any error, early.
       		cb(null);
       		return;
       	
       }
       
 
	   foundRemoteServer = localStorageGetItem("currentRemoteServer");
	   foundWifiServer = localStorageGetItem("currentWifiServer");
	   
	   
	   if((foundRemoteServer)&&(foundRemoteServer != null)&&(foundRemoteServer != "")) {
	   		//Already found a remote server
	   		//Generate the directory split, if any. Setting RAM foundServer and defaultDir
	   		var split = this.checkDefaultDir(foundRemoteServer);
	   		foundRemoteServer = split.server;
	   		foundRemoteDir = split.dir;		
	   } else {
	   		foundRemoteServer = null;
	   		foundRemoteDir = null;
	   }

   	    //Check if we have a Wifi option		
	   if((foundWifiServer)&&(foundWifiServer != null)&&(foundWifiServer != "")) {
			//Already found wifi
			//Generate the directory split, if any. Setting RAM foundServer and defaultDir
			var split = this.checkDefaultDir(foundWifiServer);
	   		foundWifiServer = split.server;
	   		foundWifiDir = split.dir;	

	   } else {
	   		foundWifiServer = null;
	   		foundWifiDir = null;
	   }
	   
	   

	   //Early out:
	   if((foundWifiServer == null)&&(foundRemoteServer == null)) {
	   		cb('No known server.');
	   		return;
	   }

	   
	   //Now try the wifi server as the first option to use if it exists:
	   if((foundWifiServer)&&(foundWifiServer != null)&&(foundWifiServer != "null")) {
	   	  //Ping the wifi server
	   	  glbThis.notify('Trying to connect to the wifi server..');
	   	  
	   	  //Timeout after 5 secs for the following ping
       	  var scanning = setTimeout(function() {
                
                
                glbThis.notify('Timeout finding your wifi server.</br>Trying remote server..');
                
                //Else can't communicate with the wifi server at this time.
	   	  	    //Try the remote server
	   	  	  	if((foundRemoteServer)&&(foundRemoteServer != null)&&(foundRemoteServer != "null")) {
	   	  	  		
	   	  	  		var scanningB = setTimeout(function() {
	   	  	  			//Timed out connecting to the remote server - that was the
	   	  	  			//last option.
	   	  	  			localStorageRemoveItem("usingServer");
	   	  	  			localStorageRemoveItem("defaultDir");
	   	  	  			localStorageRemoveItem("serverRemote");
	   	  	  			
	   	  	  			if(alreadyReturned == false) {
	   	  	  				alreadyReturned = true;
	   	  	  				cb('No server found');
	   	  	  			}
	   	  	  		
	   	  	  		}, 6000);
	   	  	  		
	   	  	  		glbThis.get(foundRemoteServer, function(url, resp) {
	   	  	  		
	   	  	  		    if(resp != "") {
							//Success, got a connection to the remote server
							
							clearTimeout(scanningB);		//Ensure we don't error out
							localStorageSetItem("usingServer", foundRemoteServer);
							localStorageSetItem("serverRemote", "true");
							localStorageSetItem("defaultDir", foundRemoteDir);
						
				
							 if(alreadyReturned == false) {
								 alreadyReturned = true;
						 
						 		 //Get any global options
        						 glbThis.getOptions(foundRemoteDir, function() {});
						 
								 cb(null);	
					
							 }	
							 
							 clearTimeout(scanning);		//Ensure we don't error out
						}	   	  	  				
	   	  	  			
	   	  	  		});
	   	  	  		
	   	  	  	} else {
                	//Only wifi existed	   	  	  			
                	localStorageRemoveItem("usingServer");
                	localStorageRemoveItem("defaultDir");
                	localStorageRemoveItem("serverRemote");
                	if(alreadyReturned == false) {
                		alreadyReturned = true;
                		cb('No server found');
                	}
                		
            	}
                
       	   }, 2000);
	   	  
	   	  //Ping the wifi server
	   	  glbThis.get(foundWifiServer, function(url, resp) {
	   	  	  
	   	  	  if(resp != "") {
	   	  	  
				  //Success, got a connection to the wifi
				  clearTimeout(scanning);		//Ensure we don't error out
				  localStorageSetItem("usingServer", foundWifiServer);
				  localStorageSetItem("defaultDir", foundWifiDir);	
				  localStorageSetItem("serverRemote", "false");				
		  
				   	
		  
				  if(alreadyReturned == false) {
					  alreadyReturned = true;
					  					  
					  cb(null);					//Success found server
				  }
			  }
	   	  
	   	  });
	   
	   } else {
	   		//OK - no wifi option - go straight to the remote server
	   		//Try the remote server
	   		glbThis.notify('Trying to connect to the remote server....');
	   		
	   		var scanning = setTimeout(function() {
	   	  	  			//Timed out connecting to the remote server - that was the
	   	  	  			//last option.
	   	  	  			localStorageRemoveItem("usingServer");
	   	  	  			localStorageRemoveItem("defaultDir");
	   	  	  			localStorageRemoveItem("serverRemote");
	   	  	  			
	   	  	  			if(alreadyReturned == false) {
	   	  	  				alreadyReturned = true;
	   	  	  				cb('No server found');
	   	  	  			}
	   	  	  		
	   	  	  		}, 6000);
	   		
			_this.get(foundRemoteServer, function(url, resp) {
				
				if(resp != "") {
					//Success, got a connection to the remote server
					localStorageSetItem("usingServer", foundRemoteServer);
					localStorageSetItem("defaultDir", foundRemoteDir);
				    localStorageSetItem("serverRemote", "true");
				
				    
        			
				
					if(alreadyReturned == false) {
						alreadyReturned = true;
						
						//Get any global options
        				glbThis.getOptions(foundRemoteDir, function() {});
        				
						cb(null);	
					
					}
					
					clearTimeout(scanning);		//Ensure we don't error out

				}
			});
	   
	   
	   }





    },
    
    
    
    
    /* Settings Functions */ 
    
    openSettings: function() {
    	//Open the settings screen
    	var html = this.listServers();
    	document.getElementById("settings").innerHTML = html;
    	
    	document.getElementById("settings-popup").style.display = "block";
    	
    },
    
    closeSettings: function() {
    	//Close the settings screen
    	document.getElementById("settings-popup").style.display = "none";
    },

    listServers: function() {
    	//List the available servers
    	var settings = this.getArrayLocalStorage("settings");
    	
    	
    	if(settings) {
	    	var html = "<ons-list><ons-list-header>Select a PC to use now:</ons-list-header>";
	    	
	    	//Convert the array into html
	    	for(var cnt=0; cnt< settings.length; cnt++) {
	    		html = html + "<ons-list-item><ons-list-item onclick='app.setServer(" + cnt + ");'>" + settings[cnt].name + "</ons-list-item><div class='right'><ons-icon icon='md-delete' onclick='app.deleteServer(" + cnt + ");'></ons-icon></div></ons-list-item>";
	    	}
	    	
	    	html = html + "</ons-list>";
    	} else {
    		var html = "<ons-list><ons-list-header>PCs Stored</ons-list-header>";
    		var html = html + "<ons-list-item><ons-list-item>Default</ons-list-item><div class='right'><ons-icon icon='md-delete'style='color:#AAA></ons-icon></div></ons-list-item>";
    		html = html + "</ons-list>";
    	}
    	return html;
    },
    
    
    
    setServer: function(serverId) {
    	//Set the server to the input server id
    	var settings = this.getArrayLocalStorage("settings");
    
    	var currentRemoteServer = settings[serverId].currentRemoteServer;			
        var currentWifiServer = settings[serverId].currentWifiServer;	
 
        localStorageRemoveItem("usingServer"); //reset the currently used server
       
        //Save the current server
        localStorageRemoveItem("defaultDir");
        
        //Remove if one of these doesn't exist, and use the other.
        if((!currentWifiServer)||(currentWifiServer == null)||(currentWifiServer =="")) {
        	localStorageRemoveItem("currentWifiServer");
        } else {
        	localStorageSetItem("currentWifiServer", currentWifiServer);
        }
        
        if((!currentRemoteServer)||(currentRemoteServer == null)||(currentRemoteServer == "")) {
        	localStorageRemoveItem("currentRemoteServer");
        } else {
        	localStorageSetItem("currentRemoteServer", currentRemoteServer);
        }
        
        //Set the localstorage
        localStorageSetItem("currentServerName", settings[serverId].name);
 	
    	
    	navigator.notification.alert("Switched to: " +  settings[serverId].name, function() {}, "Changing PC");
    	
    	//Now refresh the current server display
    	document.getElementById("currentPC").innerHTML = settings[serverId].name;
    	
    	this.closeSettings();
    	return false;
    	
    },
    
    newServer: function() {
    	//Create a new server. 
    	//This is actually effectively resetting, and we will allow the normal functions to input a new one
    	localStorageRemoveItem("usingServer");
        
        //Remove the current one
       	localStorageRemoveItem("currentRemoteServer");
        localStorageRemoveItem("currentWifiServer");

		//Record this as a new server request
		localStorageSetItem("newServer", "true");

		this.notify("Tap above to activate.");						//Clear off old notifications
        
		//Ask for a name of the current Server:
		navigator.notification.prompt(
			'Please enter a name for this PC',  					// message
			this.saveServerName,                  					// callback to invoke
			'PC Name',            									// title
			['Ok','Cancel'],             							// buttonLabels
			'Main'                 									// defaultText
		);
	
	

    	
    },
    
    deleteServer: function(serverId) {
    	//Delete an existing server
    	this.myServerId = serverId;
    	
    	navigator.notification.confirm(
	    		'Are you sure? This PC will be removed from memory.',  // message
	    		function(buttonIndex) {
	    			if(buttonIndex == 1) {
						var settings = glbThis.getArrayLocalStorage("settings");
    	
						if((settings == null)|| (settings == '')) {
							//Nothing to delete 
						} else {
						
							//Check if it is deleting the current entry
							var deleteName = settings[glbThis.myServerId].name;
							var currentServerName = localStorageGetItem("currentServerName");
    	
    						if((currentServerName) && (deleteName) && (currentServerName == deleteName)) {
    							//Now refresh the current server display
    							document.getElementById("currentPC").innerHTML = "";
    							localStorageRemoveItem("currentRemoteServer");
    							localStorageRemoveItem("currentWifiServer");
    							localStorageRemoveItem("currentServerName");
    						}

						
							settings.splice(glbThis.myServerId, 1);  			//Remove the entry entirely from array
			
							glbThis.setArrayLocalStorage("settings", settings);
						} 
		
						glbThis.openSettings();			//refresh
					}
	    		
	    		},                  						// callback to invoke
	    		'Remove PC',            					// title
	    		['Ok','Cancel']             				// buttonLabels
		);
    	
    	

    },
    

    
    saveServerName: function(results) {
    	//Save the server with a name - but since this is new,
    	//Get existing settings array
    	if(results.buttonIndex == 1) {
    		//Clicked on 'Ok'
    		
    		localStorageSetItem("currentServerName", results.input1);
 
    		//Now refresh the current server display
    		document.getElementById("currentPC").innerHTML = results.input1;
    		
    		glbThis.closeSettings();
    		return;
    	} else {
    		//Clicked on 'Exit'. Do nothing.
     		return;
    	}

     	
    },
    
    displayServerName: function() {
    	//Call this during initialisation on app startup
    	var currentServerName = localStorageGetItem("currentServerName");
    	
    	if((currentServerName) && (currentServerName != null)) {
    		//Now refresh the current server display
    		document.getElementById("currentPC").innerHTML = currentServerName;
    		
    	} else {
    		document.getElementById("currentPC").innerHTML = "";
    	}
    
    
    
    },
    
    
	saveIdInput: function(status) {
    	//Save the idInput. input true/false   true = 'start with a hash'
    	//                                     false = 'start with blank'
    	//Get existing settings array
    	if(status == true) {
    		//Show a hash by default    		
    		localStorageSetItem("initialHash", "true");
    		
    	} else {
    		//Remove the hash by default
     		localStorageSetItem("initialHash", "false");
    		
    	}
    },
    
    
    enterServerManually: function(message) {
    
        var _this = this;
        
        
        if(_this.lan) {

		   var lan = _this.lan;
		   
		 
		   if(lan == "127.0.0.") {
		   		var dispLan = "http://127.0.0.1";
		   } else {
			  
		   	   var re = /^[A-Za-z]+$/;		//Regular expression for testing if letters
		   	   
		   	   if( re.test(lan) == true) {
		   	   	 	//A letter-based domain e.g. localhost, mydomain.com.
		   	   	 	var dispLan = window.location.host;
		   	   	 	dispLan = dispLan.substring(0, dispLan.indexOf(':'));		//Remove port
		   	   	 	
		   	   	 	if(location.protocol) {
		   	   	 		if(dispLan.indexOf(location.protocol) != true) {
		   	   	 			//Add http or https to the start
		   	   	 			dispLan = location.protocol + "//" + dispLan;
		   	   	 		}
		   	   	 	}
		   	   } else {
		   	   		var dispLan = "http://" + lan + "0";	//Put a default '0' in there as an example
		   	   
		   	   }
		   }    
		} else {
		
			var dispLan = "http://127.0.0.1";
		}   
       
        
        //Ask for a name of the current Server:
		navigator.notification.prompt(
			message,  					// message
			_this.saveServerAddress,                  					// callback to invoke
			'Set Server Manually',            									// title
			['Ok','Cancel'],             							// buttonLabels
			dispLan + ':5566'                									// defaultText
		);
        
    	
		return false;
    
    },
    
    saveServerAddress: function(result) {
    
    	var _this = this;
    	
    	
    	switch(result.buttonIndex) {
    	
    		
    		case 1:
    			//Clicked on 'Ok'
    			//Called from enterServerManually
     			    			
    			currentWifiServer =  result.input1;
    			usingServer = result.input1;
    			var item = String(result.input1);
    			localStorageSetItem("currentWifiServer", item);
    			localStorageSetItem("usingServer", "");
    			
    			
    			//Now try to connect
      			glbThis.findServer(function(err) {
 					if(err) {
						glbThis.notify("Sorry, we cannot connect to the server");
						
						localStorageRemoveItem("usingServer");		//This will force a reconnection
						localStorageRemoveItem("defaultDir");
						localStorageRemoveItem("currentWifiServer");
					} else {
						//Now we are connected - so we can get the photo
						glbThis.bigButton();
					}
				});
					
    			
    			
    		break;
    		
    		
    		default:
				//Do nothing    		
    		break;
    	}
    		
    	
    	return false;
    
    
    },
    
    
    displayIdInput: function() {
    	//Call this during initialisation on app startup
    	var initialHash = localStorageGetItem("initialHash");
    		
    	if((initialHash) && (initialHash != null)) {
    		//Now refresh the current ID field
    		if(initialHash == "true") {
    			document.getElementById("always-create-folder").checked = true;
    		} else {
    			document.getElementById("always-create-folder").checked = false;
    		}
     	} 
     	
    },
    
    
    
    saveServer: function() {
        	//Run this after a successful upload
        	
        	var currentServerName = null;
        	var currentRemoteServer = null;
        	var currentWifiServer = null;
        	
        	currentServerName = localStorageGetItem("currentServerName");
			currentRemoteServer = localStorageGetItem("currentRemoteServer");
			currentWifiServer =	localStorageGetItem("currentWifiServer");
   			
   			if((!currentServerName) ||(currentServerName == null)) currentServerName = "Default";
   			if((!currentRemoteServer) ||(currentRemoteServer == null)) currentRemoteServer = "";
   			if((!currentWifiServer) ||(currentWifiServer == null)) currentWifiServer = "";	
   		
   			var settings = glbThis.getArrayLocalStorage("settings");
   			
   			//Create a new entry - which will be blank to being with
   			var newSetting = { 
   				"name": currentServerName,						//As input by the user
   				"currentRemoteServer": currentRemoteServer,
   				"currentWifiServer": currentWifiServer
   			};
   			
   			
   		
   			if((settings == null)|| (settings == '')) {
   				//Creating an array for the first time
   				var settings = [];
   				settings.push(newSetting);  					//Save back to the array
   			} else {
   				//Check if we are writing over the existing entries
   				var writeOver = false;
   				for(cnt = 0; cnt< settings.length; cnt++) {
   					if(settings[cnt].name == currentServerName) {
   						writeOver = true;
   						settings[cnt] = newSetting;
   					}
   				}
   			
   				if(writeOver == false) {
    				settings.push(newSetting);  				//Save back to the array
    			}
   			} 

    		
    		//Save back to the persistent settings
    		glbThis.setArrayLocalStorage("settings", settings);
    		
    		return;
    
    },
    
    //Array storage for app permanent settings (see http://inflagrantedelicto.memoryspiral.com/2013/05/phonegap-saving-arrays-in-local-storage/)
    setArrayLocalStorage: function(mykey, myobj) {
    	return localStorageSetItem(mykey, JSON.stringify(myobj));
    },
    
    getArrayLocalStorage: function(mykey) {
        var arrayInJSON = localStorageGetItem(mykey);
        if(arrayInJSON) {
	    	return JSON.parse(arrayInJSON);
	    } else {
	    	//Send back a blank array
	    	var ret = [];
	    	return ret;
	    }
    },
    
    
 
    refreshCookies: function() {
	
		//Call this on app initialization. Checks and runs a refresh of the cookies every year.
		//First check if we are beyond the date to refresh after
    	var oldData = document.cookie;
    	
    	var refreshDate = localStorageGetItem("rf");	//But leave a note to say it has been transitioned
     	if(refreshDate) {
    		//Check if we are after the refresh date
    		var dateToday = new Date();							
			var dateRefreshDate = new Date(refreshDate);		//Text into date format

    		if(dateToday > dateRefreshDate) {		//Should be >
     			var replaceCookies = true;		//Yes, completely replace the existing ones
				
				localStorageClear();		//Clear off any existing data
				
				var ca = oldData.split(';');
				for(var i=0; i<ca.length; i++)
				{
					var valuePair = ca[i].split('=');
					var cName = myTrim(valuePair[0]);
					var cValue = myTrim(valuePair[1]);
					if(cName && cValue && cValue != "") {
						if(cName !== "rf") {		//We don't want to use the exact same refresh date. This should not be included. A new date
							//will be generated on the next run.
							localStorageSetItem(cName, decodeURIComponent(cValue));
						}
					}
				}
				
				//Refresh the page
				location.reload();
				return false;
    		} else {
    			//Just wait, do nothing for now.
    			return true;
    		}
    	
    	
    	} else {
    		//No refresh date set. Set a cookie with the next refresh date a year from now.
    		var dateRefreshDate = new Date(new Date().setFullYear(new Date().getFullYear() + 1));

    		var refreshDate = dateRefreshDate.toString();	
    		        
    		var dd = dateRefreshDate.getDate();
        	var mm = dateRefreshDate.getMonth() + 1;
	        var yyyy = dateRefreshDate.getFullYear();
	        if (dd < 10) {
	            dd = '0' + dd;
	        }
	        if (mm < 10) {
	            mm = '0' + mm;
	        }
       		var textDate = yyyy + '-' + mm + '-' + dd ;
    		localStorageSetItem("rf", textDate);
    	}
    	
		return true;
    	
    },
    
    
    
    importCookies: function(newData) {
    
    	var newData = $('#import-raw-data').val();
    	if(newData && newData != "") {
			if(confirm("Warning: You are about to import your personal app data. Any existing app data will be replaced. Are you sure you want to continue?")) {
			
				//Raw data example: api=https%3A%2F%2Fatomjump.com%2Fapi%2F; pollingURL=https%3A%2F%2Fmedimage-wrld.atomjump.com%2Fread%2FmTUDCPUTQdzCyUnhmvJm; registrationId=https%253A%252F%252Fmedimage-wrld.atomjump.com%252Fapi%252Fphoto%252F%2523mTUDCPUCQdzCyUnhmvJm; tr=1; rf=2024-03-14; currentPhotoId=0; settings=%5B%5D; ce=exists
				
				//Readable data example:  api=https://atomjump.com/api/; pollingURL=https://medimage-wrld.atomjump.com/read/mTUDCPUTQdzCyUnhmvJm; registrationId=https%3A%2F%2Fmedimage-wrld.atomjump.com%2Fapi%2Fphoto%2F%23mTUDCPUCQdzCyUnhmvJm; tr=1; rf=2024-03-14; currentPhotoId=0; settings=[]; ce=exists
				
				
				
				localStorageClear();		//Clear off any existing data
				
				var ca = newData.split(';');
				for(var i=0; i<ca.length; i++)
				{
					var valuePair = ca[i].split('=');
					var cName = myTrim(valuePair[0]);
					var cValue = myTrim(valuePair[1]);
					if(cName && cValue) {
						
						if(cValue && cValue != "") {
							localStorageSetItem(cName, decodeURIComponent(cValue));
						}
					}
				}
				
				
				alert("Your personal data has been imported successfully.");
				
				//Refresh the page
				location.reload();
				return false;
			}
		} else {
			alert("Sorry, please copy and paste your raw data from your app's 'Settings' > 'My Data' > 'View'.");
			
		}	
		return true;
    	
    },
    
    
    
    checkTransitioningData: function() {
    	var transitioned = null;
    	   	
    	transitioned = localStorageGetItem("tr");
    	if(!transitioned) {
    		//We haven't dealt with this before
    		if(localStorage.getItem("currentServerName")) {
    			//We have some form of localStorage data already stored. Transfer old storage into new method i.e. cookies
				var items = [ "currentServerName", "currentRemoteServer", "currentWifiServer", "currentPhotoId", "initialHash", "usingServer", "defaultDir", "serverOptions", "settings"];
				for(var cnt=0; cnt < items.length; cnt++) {
				
					var item = localStorage.getItem(items[cnt]);
					if(item) {
						localStorageSetItem(items[cnt], item);
					}
				}
				
				localStorage.clear();	//Clear it all out
				localStorageSetItem("tr", "1");	//But leave a note to say it has been transitioned
			} else {
				localStorageSetItem("tr", "1");	//But leave a note to say it has been transitioned
			}
    	} 
    },
    
    
    showMyData: function() {
    	var myData = document.cookie;
    	$('#raw-data').html(myData);
    	$('#human-data').html(decodeURIComponent(myData));
    	$('#show-my-data').show();
    	return true;
    }

    


};
