package com.csc.upload;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.servlet.ServletInputStream;
import com.csc.library.session.InitialEnvironment;
import com.csc.library.utilities.CscCalendar;
import com.csc.library.utilities.UProfile;
// A Class with methods used to process a ServletInputStream
  public class HttpMultiPartParser{
          private final String lineSeparator = System.getProperty("line.separator", "\n");
          private final int ONE_MB=1024*1024*1;
          private final InitialEnvironment en= new InitialEnvironment("GLOBAL");
          private String foldername="";
          private Vector fileName=new Vector();
          private UProfile up=null;
          private String realpath="";

               public Hashtable processData(ServletInputStream is, String boundary, String saveInDir)
                          throws IllegalArgumentException, IOException {
                  if (is == null) throw new IllegalArgumentException("InputStream");
                  if (boundary == null || boundary.trim().length() < 1)
                          throw new IllegalArgumentException("\"" + boundary + "\" is an illegal boundary indicator");
                  boundary = "--" + boundary;
                  StringTokenizer stLine = null, stFields = null;
                  FileInfo fileInfo = null;
                  Hashtable dataTable = new Hashtable(5);
                  String line = null, field = null, paramName = null;
                  boolean saveFiles = (saveInDir != null && saveInDir.trim().length() > 0);
                  boolean isFile = false;
                  if (saveFiles){ // Create the required directory (including parent dirs)
                          File f = new File(saveInDir);
                          f.mkdirs();
                  }
                  line = getLine(is);
                  if (line == null || !line.startsWith(boundary))
                          throw new IOException("Boundary not found; boundary = " + boundary
                                          + ", line = " + line);
                  while (line != null){
                          if (line == null || !line.startsWith(boundary)) return dataTable;
                          line = getLine(is);
                          if (line == null) return dataTable;
                          stLine = new StringTokenizer(line, ";\r\n");
                          if (stLine.countTokens() < 2) throw new IllegalArgumentException("Bad data in second line");
                          line = stLine.nextToken().toLowerCase();
                          if (line.indexOf("form-data") < 0) throw new IllegalArgumentException("Bad data in second line");
                          stFields = new StringTokenizer(stLine.nextToken(), "=\"");
                          if (stFields.countTokens() < 2) throw new IllegalArgumentException("Bad data in second line");
                          fileInfo = new FileInfo();
                          stFields.nextToken();
                          paramName = stFields.nextToken();
                          isFile = false;
                          if (stLine.hasMoreTokens()){
                                  field    = stLine.nextToken();
                                  stFields = new StringTokenizer(field, "=\"");
                                  if (stFields.countTokens() > 1){
                                          if (stFields.nextToken().trim().equalsIgnoreCase("filename")){
                                                  fileInfo.name=paramName;
                                                  String value = stFields.nextToken();
                                                  if (value != null && value.trim().length() > 0){
                                                          fileInfo.clientFileName=value;
                                                          isFile = true;
                                                  }
                                                  else{
                                                          line = getLine(is); // Skip "Content-Type:" line
                                                          line = getLine(is); // Skip blank line
                                                          line = getLine(is); // Skip blank line
                                                          line = getLine(is); // Position to boundary line
                                                          continue;
                                                  }
                                          }
                                  }
                                  else if (field.toLowerCase().indexOf("filename") >= 0){
                                          line = getLine(is); // Skip "Content-Type:" line
                                          line = getLine(is); // Skip blank line
                                          line = getLine(is); // Skip blank line
                                          line = getLine(is); // Position to boundary line
                                          continue;
                                  }
                          }
                          boolean skipBlankLine = true;
                          if (isFile){
                                  line = getLine(is);
                                  if (line == null) return dataTable;
                                  if (line.trim().length() < 1) skipBlankLine = false;
                                  else{
                                          stLine = new StringTokenizer(line, ": ");
                                          if (stLine.countTokens() < 2)
                                                  throw new IllegalArgumentException("Bad data in third line");
                                          stLine.nextToken(); // Content-Type
                                          fileInfo.fileContentType=stLine.nextToken();
                                  }
                          }
                          if (skipBlankLine){
                                  line = getLine(is);
                                  if (line == null) return dataTable;
                          }
                          if (!isFile){
                                  line = getLine(is);
                                  if (line == null) return dataTable;
                                  dataTable.put(paramName, line);
                                  // If parameter is dir, change saveInDir to dir
                                  if (paramName.equals("dir")) saveInDir = line;
                                  line = getLine(is);
                                  continue;
                          }
                          try{
                                  OutputStream os = null;
                                  String path     = null;
                                  if (saveFiles)
                                          os = new FileOutputStream(path = getFileName(saveInDir, fileInfo.clientFileName));
                                  else os = new ByteArrayOutputStream(ONE_MB);
                                  boolean readingContent = true;
                                  byte previousLine[] = new byte[2 * ONE_MB];
                                  byte temp[] = null;
                                  byte currentLine[] = new byte[2 * ONE_MB];
                                  int read, read3;
                                  if ((read = is.readLine(previousLine, 0, previousLine.length)) == -1) {
                                          line = null;
                                          break;
                                  }
                                  while (readingContent){
                                          if ((read3 = is.readLine(currentLine, 0, currentLine.length)) == -1) {
                                                  line = null;
                                                  break;
                                          }
                                          if (compareBoundary(boundary, currentLine)){
                                                  os.write(previousLine, 0, read-2);
                                                  line = new String(currentLine, 0, read3);
                                                  break;
                                          }
                                          else{
                                                  os.write(previousLine, 0, read);
                                                  temp = currentLine;
                                                  currentLine = previousLine;
                                                  previousLine = temp;
                                                  read = read3;
                                          }//end else
                                  }//end while
                                  os.flush();
                                  os.close();
                                  if (!saveFiles){
                                          ByteArrayOutputStream baos = (ByteArrayOutputStream)os;
                                          fileInfo.setFileContents(baos.toByteArray());
                                  }
                                  else fileInfo.file = new File(path);
                                  dataTable.put(paramName, fileInfo);
                          }//end try
                          catch (IOException e) {
                                  throw e;
                          }
                  }
                  return dataTable;
          }


//           * Compares boundary string to byte array

          public boolean compareBoundary(String boundary, byte ba[]){
                  byte b;
                  if (boundary == null || ba == null) return false;
                  for (int i=0; i < boundary.length(); i++)
                          if ((byte)boundary.charAt(i) != ba[i]) return false;
                  return true;
          }

     //     Convenience method to read HTTP header lines
          public synchronized String getLine(ServletInputStream sis) throws IOException{
                  byte b[]  = new byte[1024];
                  int read = sis.readLine(b, 0, b.length), index;
                  String line = null;
                  if (read != -1){
                          line = new String(b, 0, read);
                          if ((index = line.indexOf('\n')) >= 0) line   = line.substring(0, index-1);
                  }
                  return line;
          }

          public Vector expandFileList(String[] files, boolean inclDirs){
                          Vector v = new Vector();
                          if (files == null) return v;
                          for (int i=0; i < files.length; i++) v.add (new File(URLDecoder.decode(files[i])));
                          for (int i=0; i < v.size(); i++){
                                  File f = (File) v.get(i);
                                  if (f.isDirectory()){
                                          File[] fs = f.listFiles();
                                          for (int n = 0; n < fs.length; n++) v.add(fs[n]);
                                          if (!inclDirs){
                                                  v.remove(i);
                                                  i--;
                                          }
                                  }
                          }
                          return v;
                  }

          public String getFileName(String dir, String fileName) throws IllegalArgumentException{
                  String path = null;
                  if (dir == null || fileName == null) throw new IllegalArgumentException("dir or fileName is null");
                  int index = fileName.lastIndexOf('/');
                  String name = null;
                  if (index >= 0) name = fileName.substring(index + 1);
                  else name = fileName;
                  index = name.lastIndexOf('\\');
                  if (index >= 0) fileName = name.substring(index + 1);
                  path = dir + File.separator + fileName;
                  if (File.separatorChar == '/') return path.replace('\\', File.separatorChar);
                  else return path.replace('/', File.separatorChar);
          }

          public boolean uploadFiles(Hashtable ht,UProfile u){
            boolean error=false;    
            String path="";
            if (ht.get("myFile")!=null){
            			 path = (String)ht.get("dir");
            			 FileInfo fi = (FileInfo)ht.get("myFile");
            			 File fipath=null;
            			 if(u!=null ){
            				 this.up=u;
//            				 this.deleteTempFile();
//                             path = en.getValue("TEMP-dir");
//                             path+="UPLOAD/"+this.getFoldername()+"/";
                             fipath=new File(path);
                             if(!fipath.exists())
                            	 fipath.mkdirs(); 
                             error=this.processFileAuto(fi,"",path);	
                             up.put("upload_temp_file", fileName);
            			 }else{
                             fipath=new File(path);
                             if(!fipath.exists())
                            	 fipath.mkdirs(); 
                             error=this.processFile(fi,"",path);	            				 
            			 }            			 
                 }
                 else{
                   error = false;
                 }
            return error;
          }
          
          public boolean uploadFiles(Hashtable ht){
              boolean error=uploadFiles(ht, null);
              return error;
            }
          
          private boolean processFile(FileInfo fi,String reNamefile,String path){
              File f = fi.file;
              String typefile="",file_Name="";
              String newname=f.getName();
              if(newname.indexOf(".")>-1){                         	
              	typefile=newname.substring(newname.indexOf(".")+1);
              	file_Name=newname.substring(0,newname.indexOf("."));
              }
              
              if(reNamefile.trim().length()>0){
            	  if(reNamefile.indexOf(".")>-1)
              	      newname=reNamefile;
            	  else
            		  newname=reNamefile+"."+typefile;
              }
              
              if (!path.endsWith(File.separator)) 
            	  path = path+File.separator;

            if (!f.renameTo(new File(path+newname))){
                f.delete();
                return true;
              }              
        	  return false;
          }
          
          private boolean processFileAuto(FileInfo fi,String reNamefile,String path){
              File f = fi.file;
              String typefile="",file_Name="";
              if(f.getName().lastIndexOf(".")>-1){                         	
              	typefile=f.getName().substring(f.getName().lastIndexOf(".")+1);
              	file_Name=f.getName().substring(0,f.getName().lastIndexOf("."));
              }
              String newname=this.createFilename("."+typefile);                                       
              if (!path.endsWith(File.separator)) 
            	  path = path+File.separator;
              
              fileName.addElement(newname);
              
              if (!f.renameTo(new File(path+newname))){
                f.delete();
                return true;
              }              
        	  return false;
          }          
          
          private String createFilename(String postfix){
        	  CscCalendar cs=new CscCalendar();
        	  String filename=String.valueOf(cs.getTimeInMillis())+postfix;
        	  if(fileName.contains(filename))
        		  filename=this.createFilename(postfix);
        	  return filename;
          }
          
          public boolean uploadMultiFilesAuto(Hashtable ht,String reqname,String reNamefile){
              boolean error=false;
              if (ht.get(reqname)!=null){
                           FileInfo fi = (FileInfo)ht.get(reqname);
                           String path = (String)ht.get("dir");
//                           String path = en.getValue("TEMP-dir");
//                           path+="UPLOAD/"+this.getFoldername();
                           File fipath=new File(path);
                           if(!fipath.exists())
                          	 fipath.mkdirs();                                                  
                           error=this.processFileAuto(fi,"",path);
                   }
                   else{
                     error = false;
                   }
              return error;
            }
          
          public boolean uploadMultiFiles(Hashtable ht,String reqname,String reNamefile){
            boolean error=false;
            if (ht.get(reqname)!=null){
                         FileInfo fi = (FileInfo)ht.get(reqname);
                         String path = (String)ht.get("dir");
                         File fipath=new File(path);
                         if(!fipath.exists())
                        	 fipath.mkdirs();                                                  
                         error=this.processFile(fi,reNamefile,path);
                 }
                 else{
                   error = false;
                 }
            return error;
          }

          public boolean uploadMultiFiles(Hashtable ht,String reqname,String reNamefile,String path){
              boolean error=false;
              if (ht.get(reqname)!=null){
                  File fipath=new File(path);
                  if(!fipath.exists())
                 	 fipath.mkdirs();                         
            	  
            	  FileInfo fi = (FileInfo)ht.get(reqname);
            	  error=this.processFile(fi,reNamefile,path);
                   }else{
                     error = false;
                   }
              return error;
            }          
          
          public boolean uploadMultiFiles(Hashtable ht,String fileList){
        	  UProfile u=null;
              boolean error=uploadMultiFiles(ht,fileList,u);
              return error;
            }          
          
          public boolean uploadMultiFiles(Hashtable ht,String fileList,UProfile u){
              boolean error=false;
              String fList=(String)ht.get(fileList);
              StringTokenizer stk=new StringTokenizer(fList,",");
              Vector v=new Vector();
              while(stk.hasMoreTokens()){
            	 v.addElement((String)stk.nextElement());
              }
              if(u==null){
            	  this.uploadMultiFiles(ht,v);
              }else{
            	  this.uploadMultiFiles(ht, v,u);
              }
              return error;
            } 
          
          public boolean uploadMultiFiles(Hashtable ht,Vector filelist){
              boolean error=false;
              if(filelist.size()>0){
            	  String path= (String) ht.get("dir");
                  File fipath=new File(path);
                  if(!fipath.exists())
                 	 fipath.mkdirs();                                     	 
            	  String fname="";
            	   for(int c=0;c<filelist.size();c++){
            		   fname=(String)filelist.get(c);
            		   FileInfo fi = (FileInfo)ht.get(fname);
            		   this.processFile(fi,"",path);            		   
            	   }
            	   error=true;
                   }
                   else{
                     error = false;
                   }
              return error;
            }
          
          public boolean uploadMultiFiles(Hashtable ht,Vector filelist,UProfile u){
              boolean error=false;
              if(filelist.size()>0){
                  this.up=u;
                  String path = (String)ht.get("dir");
//            	  this.deleteTempFile();            	  
//                  String path = en.getValue("TEMP-dir");
//                  path+="UPLOAD/"+this.getFoldername();
                  File fipath=new File(path);
                  if(!fipath.exists())
                 	 fipath.mkdirs();                                     	 
            	  String fname="";
            	   for(int c=0;c<filelist.size();c++){
            		   fname=(String)filelist.get(c);
            		   FileInfo fi = (FileInfo)ht.get(fname);
            		   this.processFileAuto(fi,"",path);            		   
            	   }
            	   up.put("upload_temp_file", fileName);
            	   error=true;
                   }
                   else{
                     error = false;
                   }
              return error;
            }
          
          public boolean deleteFile(Hashtable ht,String reqname){
            boolean error=false;
            if (ht.get(reqname)!=null){
                         FileInfo fi = (FileInfo)ht.get(reqname);
                         File f = fi.file;
                           f.delete();
                           error=true;
                 }
                 else{
                   error = false;
                 }
            return error;
          }


		/**
		 * @return the foldername
		 */
		public String getFoldername() {
			if(up.containsKey("upload_temp_folder")){
				this.setFoldername(up.get("upload_temp_folder"));
			}else{
			if(this.foldername.length()==0){
                  CscCalendar cs=new CscCalendar();
                  this.setFoldername(String.valueOf(cs.getTimeInMillis()));
                  up.set("upload_temp_folder", this.foldername);
        	  }
			}
			return foldername;
		}


		/**
		 * @param foldername the foldername to set
		 */
		public void setFoldername(String foldername) {
			this.foldername = foldername;
		}

		private void deleteTempFile(){
			File fipath=null;
        	if(up.containsKey("upload_temp_file")){
        		fileName=(Vector)up.getObject("upload_temp_file");
        		for(int c=0;c<fileName.size();c++){
        			fipath=new File(en.getValue("TEMP-dir")+"UPLOAD/"+this.getFoldername()+"/"+fileName.get(c).toString());
        			if(fipath.isFile()&& fipath.exists()){
        				fipath.delete();
        				fileName.remove(c);
        				c--;
        			}
        		}
        	}
		}


		/**
		 * @return the realpath
		 */
		public String getRealpath() {			
			return realpath;
		}


		/**
		 * @param realpath the realpath to set
		 */
		public void setRealpath(String realpath) {
			if(up!=null){
				up.set("upload_realpath", realpath);
			}
			this.realpath = realpath;
		}
		
		public String getStringFile(){
			String filelist="";
			for(int v=0;v<fileName.size();v++){
				if(v!=0 && v<fileName.size()-1)
					filelist+=",";
				filelist+=(String)fileName.get(v);
			}
			return filelist;
		}
		
		public Vector getVectorFile(){
			return fileName;
		}		
  
  } //End of class HttpMultiPartParser