content: package aliview.aligner;
  
  import java.io.BufferedInputStream;
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileNotFoundException;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.math.BigInteger;
  import java.security.MessageDigest;
  import java.security.NoSuchAlgorithmException;
  import java.text.SimpleDateFormat;
  
  import org.apache.commons.io.FileUtils;
  import org.apache.commons.io.IOUtils;
  import org.apache.log4j.Logger;
  
  import utils.OSNativeUtils;
  
  
  public class MuscleWrapper {
  
  	public static void main(String[] args) {
  		getMusclePath();
  	}
  
  	private static final Logger logger = Logger.getLogger(MuscleWrapper.class);
  
  	public static File getMusclePath(){
  
  		// get predefined path
  
  		// if no predefined path create one for distributed program
  		File localMuscleBinFile = new File(getAliViewUserDataDirectory(), "/binaries" + File.separator + getMuscleBinDependingOnOS());
  
  		//logger.info("localMuscleBinFile.lastModified()" + localMuscleBinFile.lastModified());
  		//SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
  		//System.out.println("After Format : " + sdf.format(localMuscleBinFile.lastModified()));
  
  		// check if file exist if not extract it from jar
  		if(! localMuscleBinFile.exists() || localMuscleBinFile.length() == 0 || localMuscleBinFile.lastModified() < 1395868152000L){ // modified date = 20140326 22:09:12 (this is the date when saving file problem finally was resolved)
  			ClassLoader cl = MuscleWrapper.class.getClassLoader();	
  			try {
  				boolean fileISOK = false;
  				int nTries = 0;
  				while(! fileISOK && nTries <=3){
  					nTries ++;
  					InputStream muscleStreamFromJar = cl.getResourceAsStream(localMuscleBinFile.getName());
  					logger.info(muscleStreamFromJar);
  					copyMuscleFileToLocalDir(muscleStreamFromJar, localMuscleBinFile);
  					// reopen stream
  					muscleStreamFromJar = cl.getResourceAsStream(localMuscleBinFile.getName());
  					fileISOK = verifyMD5(muscleStreamFromJar, localMuscleBinFile);
  					if(! fileISOK){
  						FileUtils.deleteQuietly(localMuscleBinFile);
  					}else{
  						localMuscleBinFile.setExecutable(true);
  					}
  				}
  
  			} catch (IOException e) {
  				// TODO Auto-generated catch block
  				e.printStackTrace();
  				// TODO Maybe notify something went wrong with installing muscle
  			}
  
  		}
  
  		logger.info(localMuscleBinFile);		
  		return localMuscleBinFile;
  
  	}
  
  
  	private static boolean verifyMD5(InputStream streamFromJar,File localMuscleBinFile) throws FileNotFoundException {
  		boolean checksumOK = false;
  		String checksum1 = checkSum(streamFromJar);
  		String checksum2 = checkSum(new FileInputStream(localMuscleBinFile));
  		logger.info(checksum1);
  		logger.info(checksum2);
  		if(checksum1 != null && checksum2 != null && checksum1.equals(checksum2)){
  			checksumOK = true;
  		}
  		return checksumOK;
  	}
  
  
  	private static void copyMuscleFileToLocalDir(InputStream muscleStreamFromJar, File localMuscleBinFile) throws IOException {
  		FileUtils.forceMkdir(localMuscleBinFile.getParentFile());
  		FileUtils.copyInputStreamToFile(muscleStreamFromJar, localMuscleBinFile);		
  	}
  
  
  	public static final String getAliViewUserDataDirectory() {
  		return System.getProperty("user.home") + File.separator + ".AliView";
  	}
  
  
  
  	public static final String getMuscleBinDependingOnOS() {
  
  		String binName = "";
  		// 64-bit
  		if(OSNativeUtils.is64BitOS()){
  			if(OSNativeUtils.isMac()){
  				binName = "muscle3.8.31_i86darwin64";
  			}
  			else if(OSNativeUtils.isLinuxOrUnix()){
  				binName = "muscle3.8.425_i86linux64";
  			}
  			// default
  			else{
  				binName = "muscle3.8.425_win32.exe";
  			}
  			// 32-bit
  		}else{
  			if(OSNativeUtils.isMac()){
  				if(OSNativeUtils.isPowerPC()){
  					binName = "muscle3.8.31_macppc";
  				}
  				else{
  					binName = "muscle3.8.31_i86darwin32";
  				}
  			}
  			else if(OSNativeUtils.isLinuxOrUnix()){
  				binName = "muscle3.8.425_i86linux32";
  			}
  			// default
  			else{
  				binName = "muscle3.8.425_win32.exe";
  			}
  		}
  
  		return binName;
  
  	}
  
  	/*
  	 * Calculate checksum of a File using MD5 algorithm
  	 */
  	public static String checkSum(InputStream instream){
  		String checksum = null;
  
  		try {
  			BufferedInputStream bis = new BufferedInputStream(instream);
  			MessageDigest md = MessageDigest.getInstance("MD5");
  
  			//Using MessageDigest update() method to provide input
  			byte[] buffer = new byte[8192];
  			int numOfBytesRead;
  			while( (numOfBytesRead = bis.read(buffer)) > 0){
  				md.update(buffer, 0, numOfBytesRead);
  			}
  			byte[] hash = md.digest();
  			checksum = new BigInteger(1, hash).toString(16); //don't use this, truncates leading zero
  		} catch (FileNotFoundException e) {
  			// TODO Auto-generated catch block
  			e.printStackTrace();
  		} catch (NoSuchAlgorithmException e) {
  			// TODO Auto-generated catch block
  			e.printStackTrace();
  		} catch (IOException e) {
  			// TODO Auto-generated catch block
  			e.printStackTrace();
  		}
  
  		return checksum;
  	}
  
  
  }
  
  
  