package railo.commons.io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.Reader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.sql.ResultSet;
import java.util.LinkedList;
import java.util.zip.ZipFile;

import javax.mail.Transport;

import net.sf.jmimemagic.Magic;
import net.sf.jmimemagic.MagicMatch;
import railo.commons.io.res.Resource;
import railo.commons.lang.StringUtil;
import railo.commons.net.URLEncoder;
import railo.runtime.exp.PageException;

import com.lowagie.text.Document;

/**
 * I/O Util 
 */
public final class IOUtil {

    /**
     * copy a inputstream to a outputstream
     * @param in 
     * @param out
     * @param closeIS 
     * @param closeOS 
     * @throws IOException
     */
    public static final void copy(InputStream in, OutputStream out, boolean closeIS, boolean closeOS) throws IOException {
    	try {
            copy(in,out,0xffff);
        }
        finally {
            if(closeIS)closeEL(in);
            if(closeOS)closeEL(out);
        }
    }
    
    /**
     * copy a inputstream to a outputstream
     * @param in 
     * @param out
     * @param closeIS 
     * @param closeOS 
     * @throws IOException
     */
    public static final void merge(InputStream in1, InputStream in2, OutputStream out, boolean closeIS1, boolean closeIS2, boolean closeOS) throws IOException {
    	try {
            merge(in1,in2,out,0xffff);
        }
        finally {
            if(closeIS1)closeEL(in1);
            if(closeIS2)closeEL(in2);
            if(closeOS)closeEL(out);
        }
    }
    
    /**
     * copy a inputstream to a outputstream
     * @param in 
     * @param out
     * @param closeIS 
     * @param closeOS 
     * @throws IOException
     */
    public static final void copy(OutputStream out, InputStream in,boolean closeIS, boolean closeOS) throws IOException {
    	copy(in,out,closeIS,closeOS);
    }
    
	/**
	 * copy a input resource to a output resource
     * @param in
	 * @param out
	 * @throws IOException
	 */
	public static void copy(Resource in, Resource out) throws IOException {
		in.copyTo(out, false);
	}
	
	public static void merge(Resource in1, Resource in2, Resource out) throws IOException {
		InputStream is1=null;
		InputStream is2=null;
		OutputStream os=null;
		try {
			is1=toBufferedInputStream(in1.getInputStream());
			is2=toBufferedInputStream(in2.getInputStream());
			os=toBufferedOutputStream(out.getOutputStream());
		}
		catch(IOException ioe) {
			IOUtil.closeEL(is1);
			IOUtil.closeEL(is2);
			IOUtil.closeEL(os);
			throw ioe;
		}
		merge(is1,is2,os,true,true,true);
	}

	/**
	 * copy a input resource to a output resource
     * @param in
	 * @param out
	 * @throws IOException
	 */
	public static void copy(InputStream is, Resource out, boolean closeIS) throws IOException {
		OutputStream os=null;
		try {
			os=toBufferedOutputStream(out.getOutputStream());
		}
		catch(IOException ioe) {
			IOUtil.closeEL(os);
			throw ioe;
		}
		copy(is,os,closeIS,true);
	}
    
	/**
	 * copy a input resource to a output resource
     * @param in
	 * @param out
	 * @throws IOException
	 */
	public static void copy(Resource in, OutputStream os, boolean closeOS) throws IOException {
		InputStream is=null;
		try {
			is=toBufferedInputStream(in.getInputStream());
		}
		catch(IOException ioe) {
			IOUtil.closeEL(is);
			throw ioe;
		}
		copy(is,os,true,closeOS);
	}
    
    public static final void copy(InputStream in, OutputStream out, int offset, int length) throws IOException {
    	copy(in, out, offset, length,0xffff);
    }
    
    public static final void copy(InputStream in, OutputStream out, long offset, long length) throws IOException {
    	int len;
        byte[] buffer;
        int block=0xffff;
    	
    	// first offset to start
    	if(offset>0) {
    		long skipped=0;
    		try{
    			skipped = in.skip(offset);
    		}
    		catch(Throwable t){}
    		
			if(skipped<=0) {
	    		while(true) {
	            	if(block>offset)block=(int)offset;
	            	buffer = new byte[block];
	            	len = in.read(buffer);
	            	if(len==-1) throw new IOException("reading offset is bigger than input itself");
	            	//dnos.write(buffer, 0, len);
	            	offset-=len;
	            	if(offset<=0) break;
	            }
    		}
    	}
    	
    	// write part
    	if(length<0) {
    		copy(in, out,block);
    		return;
    	}
    	
    	while(true) {
        	if(block>length)block=(int) length;
        	buffer = new byte[block];
        	len = in.read(buffer);
        	if(len==-1) break;
        	out.write(buffer, 0, len);
        	length-=len;
        	if(length<=0) break;
        }
    }
    
    public static final void copy(InputStream in, OutputStream out, int offset, int length, int blockSize) throws IOException {

        int len;
        byte[] buffer;
        int block;//0xffff;
    	
    	// first offset to start
    	if(offset>0) {
    		long skipped=0;
    		try{
    			skipped = in.skip(offset);
    		}
    		catch(Throwable t){}
    		
			if(skipped<=0) {
	    		block = blockSize;//0xffff;
	        	while(true) {
	            	if(block>offset)block=offset;
	            	buffer = new byte[block];
	            	len = in.read(buffer);
	            	if(len==-1) throw new IOException("reading offset is bigger than input itself");
	            	//dnos.write(buffer, 0, len);
	            	offset-=len;
	            	if(offset<=0) break;
	            }
			}
    	}
    	
    	// write part
    	if(length<0) {
    		copy(in, out,blockSize);
    		return;
    	}
    	block = blockSize;//0xffff;
    	while(true) {
        	if(block>length)block=length;
        	buffer = new byte[block];
        	len = in.read(buffer);
        	if(len==-1) break;
        	out.write(buffer, 0, len);
        	length-=len;
        	if(length<=0) break;
        }
    }

	/**
     * copy a inputstream to a outputstream
     * @param in 
     * @param out
     * @param blockSize 
     * @throws IOException
     */
    private static final void copy(InputStream in, OutputStream out, int blockSize) throws IOException {
        byte[] buffer = new byte[blockSize];
        int len;
        while((len = in.read(buffer)) !=-1) {
          out.write(buffer, 0, len);
        }
    }
    
    private static final void merge(InputStream in1, InputStream in2, OutputStream out, int blockSize) throws IOException {
    	copy(in1, out,blockSize);
    	copy(in2, out,blockSize);
    }
    
    /**
     * copy a reader to a writer
     * @param r 
     * @param w 
     * @throws IOException
     */
    private static final void copy(Reader r, Writer w) throws IOException {
        copy(r,w,0xffff);
    }
    
    /**
     * copy a reader to a writer
     * @param reader 
     * @param writer 
     * @param closeReader 
     * @param closeWriter 
     * @throws IOException
     */
    public static final void copy(Reader reader, Writer writer, boolean closeReader, boolean closeWriter) throws IOException {
        try {
            copy(reader,writer,0xffff);
        }
        finally {
            if(closeReader)closeEL(reader);
            if(closeWriter)closeEL(writer);
        }
    }
    
    /**
     * copy a reader to a writer
     * @param r 
     * @param w 
     * @param blockSize 
     * @throws IOException
     */
    private static final void copy(Reader r, Writer w, int blockSize) throws IOException {
        char[] buffer = new char[blockSize];
        int len;

        while((len = r.read(buffer)) !=-1)
          w.write(buffer, 0, len);
    }
    
    /** 
     * copy content of in file to out File 
     * @param in input 
     * @param out output 
     * @throws IOException 
     */ 
    public void copy(File in,File out) throws IOException {
    	InputStream is=null;
    	OutputStream os=null;
		try {
			is = new BufferedFileInputStream(in);
			os = new BufferedFileOutputStream(out);
		} 
		catch (IOException ioe) {
			closeEL(is,os);
			throw ioe;
		}
    	copy(is,os,true,true); 
    } 

    
    
    

    /**
     * close inputstream without a Exception
     * @param is 
     * @param os 
     */
     public static void closeEL(InputStream is, OutputStream os) {
          closeEL(is);
          closeEL(os);
      }
     
    /**
     * close inputstream without a Exception
     * @param is 
     */
     public static void closeEL(InputStream is) {
    	 try {
    		 if(is!=null)is.close();
    	 } 
    	 //catch (AlwaysThrow at) {throw at;}
    	 catch (Throwable t) {}
     }
     
     public static void closeEL(ZipFile zip) {
    	 try {
    		 if(zip!=null)zip.close();
    	 } 
    	 //catch (AlwaysThrow at) {throw at;}
    	 catch (Throwable t) {}
     }
     
     /**
      * close outputstream without a Exception
      * @param os 
      */
     public static void closeEL(OutputStream os) {
           try {
               if(os!=null)os.close();
         } 
      	 //catch (AlwaysThrow at) {throw at;}
         catch (Throwable e) {}
       }
     
     public static void closeEL(ResultSet rs) {
         try {
             if(rs!=null)rs.close();
       } 
       catch (Throwable e) {}
     }
     
     /**
      * close Reader without a Exception
      * @param r 
      */
     public static void closeEL(Reader r) {
           try {
               if(r!=null)r.close();
         } 
         //catch (AlwaysThrow at) {throw at;}
         catch (Throwable e) {}
       }

     
     /**
      * close Closeable without a Exception
      * @param r 
      */
     public static void closeEL(Closeable c ) {
           try {
               if(c!=null)c.close();
         } 
         //catch (AlwaysThrow at) {throw at;}
         catch (Throwable e) {}
       }
     
     /**
      * close Writer without a Exception
      * @param w 
      */
     public static void closeEL(Writer w) {
    	 try {
               if(w!=null)w.close();
         } 
      	 //catch (AlwaysThrow at) {throw at;}
         catch (Throwable e) {}
     }
     
     /**
      * close Writer without a Exception
      * @param w 
      */
     public static void closeEL(Transport t) {
           try {
               if(t!=null && t.isConnected())t.close();
         } 
         catch (Throwable e) {}
     }
     
     
     public static void closeEL(Document doc) {
           try {
               if(doc!=null)doc.close();
         } 
         catch (Throwable e) {}
     }
     
     
     
     /**
     * call close method from any Object with a close method.
     * @param obj
     */
     public static void closeEL(Object obj) {
         if(obj instanceof InputStream)         IOUtil.closeEL((InputStream)obj);
         else if(obj instanceof OutputStream)   IOUtil.closeEL((OutputStream)obj);
         else if(obj instanceof Writer)         IOUtil.closeEL((Writer)obj);
         else if(obj instanceof Reader)         IOUtil.closeEL((Reader)obj);
         else if(obj instanceof Closeable)         IOUtil.closeEL((Closeable)obj);
         else if(obj instanceof ZipFile)        IOUtil.closeEL((ZipFile)obj);
         else if(obj instanceof ResultSet)        IOUtil.closeEL((ResultSet)obj);
         else {
             try {
                 Method method = obj.getClass().getMethod("close",new Class[0]);
                 method.invoke(obj,new Object[0]);
             } 
             catch (Throwable e) {}
         }
     }

    /**
     * @deprecated use instead <code>{@link #getReader(Resource, Charset)}</code>
     * @param res
     * @param charset
     * @return
     * @throws IOException
     */
  	public static Reader getReader(Resource res, String charset) throws IOException {
  		return getReader(res, CharsetUtil.toCharset(charset));
  	}
  	
 	public static Reader getReader(Resource res, Charset charset) throws IOException {
 		/*
 		00 00 FE FF  	UTF-32, big-endian
 		FF FE 00 00 	UTF-32, little-endian
 		*/
 		
 		
 		InputStream is=null;
 		try {
	 		is = res.getInputStream();
	 		boolean markSupported=is.markSupported();
	        if(markSupported) is.mark(4);
	        int first = is.read();
	        int second = is.read();
	        // FE FF 	UTF-16, big-endian
	        if (first == 0xFE && second == 0xFF)    {
	        	return _getReader(is, CharsetUtil.UTF16BE);
	        }
	        // FF FE 	UTF-16, little-endian
	        if (first == 0xFF && second == 0xFE)    {
	        	return _getReader(is, CharsetUtil.UTF16LE);
	        }
	        
	        int third=is.read();
	        // EF BB BF 	UTF-8
	        if (first == 0xEF && second == 0xBB && third == 0xBF)    {
	        	//is.reset();
	 			return _getReader(is,CharsetUtil.UTF8);
	        }
	 		/*
	        int forth=is.read();
	        // 00 00 FE FF  	UTF-32, big-endian
	        if (first == 0x00 && second == 0x00 && third == 0xFE  && forth == 0xFF)    {
	        	is.reset();
	 			return _getReader(is, "utf-32");
	        }
	        // FF FE 00 00 	UTF-32, little-endian
	        if (first == 0xFF && second == 0xFE && third == 0x00  && forth == 0x00)    {
	        	is.reset();
	 			return _getReader(is, "utf-32");
	        }*/
	        
	        if(markSupported) {
	    		is.reset();
	    		return _getReader(is,charset);
	    	}
 		}
 		catch(IOException ioe) {
 			IOUtil.closeEL(is);
 			throw ioe;
 		}
 		
 	// when mark not supported return new reader
        closeEL(is);
        is=null;
 		try {
 			is=res.getInputStream();
 		}
 		catch(IOException ioe) {
 			closeEL(is);
 			throw ioe;
 		}
        return _getReader(is, charset);             
   }

 	public static Reader getReader(InputStream is, Charset charset) throws IOException {
 	 		
 	 		boolean markSupported=is.markSupported();
 	        if(!markSupported) return _getReader(is, charset);
 	        
 	        if(markSupported) is.mark(4);
 	        
 	        int first = is.read();
 	        int second = is.read();
 	        // FE FF 	UTF-16, big-endian
 	        if (first == 0xFE && second == 0xFF)    {
 	        	//is.reset();
 	 			return _getReader(is, CharsetUtil.UTF16BE);
 	        }
 	        // FF FE 	UTF-16, little-endian
 	        if (first == 0xFF && second == 0xFE)    {
 	 			return _getReader(is, CharsetUtil.UTF16LE);
 	        }
 	        
 	        int third=is.read();
 	        // EF BB BF 	UTF-8
 	        if (first == 0xEF && second == 0xBB && third == 0xBF)    {
 	        	return _getReader(is, CharsetUtil.UTF8);
 	        }

 	 		is.reset();
 	    	return _getReader(is,charset);       
 	   }
 	 	
 	/**
 	 * @deprecated use instead <code>{@link #getReader(InputStream, Charset)}</code>
 	 * @param is
 	 * @param charset
 	 * @return
 	 * @throws IOException
 	 */
 	public static Reader getReader(InputStream is, String charset) throws IOException {
 		return getReader(is, CharsetUtil.toCharset(charset));    
    }
 	 
     /**
      * returns a Reader for the given InputStream
      * @param is
      * @param charset
      * @return Reader
      * @throws IOException
      */
	 private static Reader _getReader(InputStream is, Charset charset) throws IOException {
		 if(charset==null) charset=SystemUtil.getCharset();
	     return new BufferedReader(new InputStreamReader(is,charset));
	 }

    /**
     * @deprecated use instead <code>{@link #toString(InputStream, Charset)}</code>
     * @param is
     * @param charset
     * @return
     * @throws IOException
     */
     public static String toString(InputStream is, String charset) throws IOException {
         return toString(is,CharsetUtil.toCharset(charset));
     }
     
     /**
     * reads string data from a InputStream
     * @param is
     * @param charset 
     * @return string from inputstream
    * @throws IOException 
    */
     public static String toString(InputStream is, Charset charset) throws IOException {
         return toString(getReader(is,charset));
     }
     
     /**
      * @deprecated use instead <code>{@link #toString(byte[], Charset)}</code>
      * @param barr
      * @param charset
      * @return
      * @throws IOException
      */
     public static String toString(byte[] barr, String charset) throws IOException {
         return toString(barr,CharsetUtil.toCharset(charset));
     }
     
     public static String toString(byte[] barr, Charset charset) throws IOException {
         return toString(getReader(new ByteArrayInputStream(barr),charset));
     }
     
     
   /**
    * reads String data from a Reader
    * @param reader
    * @return readed string
    * @throws IOException
    */
   public static String toString(Reader reader) throws IOException {
       StringWriter sw=new StringWriter(512);
       copy(toBufferedReader(reader),sw);
       sw.close();
       return sw.toString();
   }

   /**
    * reads String data from a Reader
    * @param reader
    * @return readed string
    * @throws IOException
    */
   public static String toString(Reader reader,boolean buffered) throws IOException {
       StringWriter sw=new StringWriter(512);
       if(buffered)copy(toBufferedReader(reader),sw);
       else copy(reader,sw);
       sw.close();
       return sw.toString();
   }

   /**
    * @deprecated use instead <code>{@link #toString(Resource, Charset)}</code>
    * @param file
    * @param charset
    * @return
    * @throws IOException
    */
   public static String toString(Resource file, String charset) throws IOException {
	   return toString(file, CharsetUtil.toCharset(charset));
   }
   
   /**
    * reads String data from File
     * @param file 
     * @param charset 
     * @return readed string
    * @throws IOException
    */
   public static String toString(Resource file, Charset charset) throws IOException {
       Reader r = null;
       try {
    	   r = getReader(file,charset);
           String str = toString(r);
           return str;
       }
       finally {
           closeEL(r);
       }
   }

    /**
     * @param reader Reader to get content from it
     * @return returns the content of the file as String Array (Line by Line)
     * @throws IOException
     */
    public static String[] toStringArray(Reader reader) throws IOException {
        if(reader==null)return new String[0];
        BufferedReader br = new BufferedReader(reader); 
        LinkedList<String> list=new LinkedList<String>();
        
        String line;
        while((line=br.readLine())!=null)   {
            list.add(line);
        }
        br.close();
        String[] content=new String[list.size()];
        int count=0;
        while(!list.isEmpty()) {
            content[count++]=list.removeFirst();
        }
        return content;
    }

    /**
     * @deprecated use instead <code>{@link #write(Resource, String, Charset, boolean)}</code> 
     * writes a String to a object
     * @param file 
     * @param string String to write to file
     * @param charset
     * @param append  append to cuuretn data or overwrite existing data
     * @throws IOException
     */
    public static void write(File file, String string, String strCharset, boolean append) throws IOException {
        Charset charset;
    	if(StringUtil.isEmpty(strCharset)) {
            charset=SystemUtil.getCharset();
        }  
    	else charset=CharsetUtil.toCharset(strCharset);
    		
        OutputStreamWriter writer=null;
        try {
            writer=new OutputStreamWriter(new BufferedFileOutputStream(file,append),charset);
            writer.write(string);
            
        }
        finally {
            closeEL(writer);
        }
    }
    
    /**
     * @deprecated use instead <code>{@link #write(Resource, String, Charset, boolean)}</code>
     * @param res
     * @param string
     * @param charset
     * @param append
     * @throws IOException
     */
    public static void write(Resource res, String string, String charset, boolean append) throws IOException {
    	write(res, string, CharsetUtil.toCharset(charset), append);
    }
    
    public static void write(Resource res, String string, Charset charset, boolean append) throws IOException {
        if(charset==null) {
            charset=SystemUtil.getCharset();
        }
                
        
        Writer writer=null;
        try {
            writer=getWriter(res, charset,append);
            writer.write(string);
        }
        finally {
            closeEL(writer);
        }
    }


    public static void write(Resource res, byte[] barr) throws IOException {
        ByteArrayInputStream bais = new ByteArrayInputStream(barr);
    	OutputStream os=IOUtil.toBufferedOutputStream(res.getOutputStream());
        IOUtil.copy(bais, os, true, true);
    }

    public static void write(Resource res, byte[] barr, boolean append) throws IOException {
        ByteArrayInputStream bais = new ByteArrayInputStream(barr);
    	OutputStream os=IOUtil.toBufferedOutputStream(res.getOutputStream(append));
        IOUtil.copy(bais, os, true, true);
    }
    
    /**
     * @deprecated use instead <code>{@link #toBytes(Resource)}</code> 
     * @param file 
     * @return returns the Content of the file as byte array
     * @throws IOException
     */
    public static byte[] toBytes(File file) throws IOException {
        BufferedFileInputStream bfis = null;
        try {
        	bfis = new BufferedFileInputStream(file);
            byte[] barr = toBytes(bfis);
            return barr;
        }
        finally {
            closeEL(bfis);
        }
    }
    
    /**
     * @param res 
     * @return returns the Content of the file as byte array
     * @throws IOException
     */
    public static byte[] toBytes(Resource res) throws IOException {
    	BufferedInputStream bfis = null;
        try {
        	bfis = toBufferedInputStream(res.getInputStream());
            byte[] barr = toBytes(bfis);
            return barr;
        }
        finally {
            closeEL(bfis);
        }
    }

    public static BufferedInputStream toBufferedInputStream(InputStream is) {
		if(is instanceof BufferedInputStream) return (BufferedInputStream) is;
		return new BufferedInputStream(is);
	}
    
    public static BufferedOutputStream toBufferedOutputStream(OutputStream os) {
		if(os instanceof BufferedOutputStream) return (BufferedOutputStream) os;
		return new BufferedOutputStream(os);
	}
    
    public static BufferedReader toBufferedReader(Reader r) {
		if(r instanceof BufferedReader) return (BufferedReader) r;
		return new BufferedReader(r);
	}

    /**
     * @deprecated use instead <code>{@link #getBufferedReader(Resource, Charset)}</code>
     * @param res
     * @param charset
     * @return
     * @throws IOException
     */
    public static BufferedReader getBufferedReader(Resource res,String charset) throws IOException {
		return getBufferedReader(res,CharsetUtil.toCharset(charset));
	}
    
    public static BufferedReader getBufferedReader(Resource res,Charset charset) throws IOException {
		return toBufferedReader(getReader(res, charset));
	}
    
    
    public static BufferedWriter toBufferedWriter(Writer w) {
		if(w instanceof BufferedWriter) return (BufferedWriter) w;
		return new BufferedWriter(w);
	}

	/**
     * @param is 
     * @return returns the Content of the file as byte array
     * @throws IOException
     */
    public static byte[] toBytes(InputStream is) throws IOException {
       return toBytes(is,false);
    }
    

    public static byte[] toBytes(InputStream is, boolean closeStream) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        copy(is,baos,closeStream,true);
        return baos.toByteArray();
    }

    public static byte[] toBytesMax(InputStream is, int max) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        copy(is,baos,0,max);
        return baos.toByteArray();
    }

    /**
     * flush OutputStream without a Exception
     * @param os
     */
    public static void flushEL(OutputStream os) {
        try {
            if(os!=null)os.flush();
        } catch (Exception e) {}
    }

    /**
     * flush OutputStream without a Exception
     * @param os
     */
    public static void flushEL(Writer w) {
        try {
            if(w!=null)w.flush();
        } catch (Exception e) {}
    }
    
    /**
     * check if given encoding is ok
     * @param encoding
     * @throws PageException 
     */
    public static void checkEncoding(String encoding) throws IOException {
		try {
			URLEncoder.encode("", encoding);
		} catch (UnsupportedEncodingException e) {
			throw new IOException("invalid encoding ["+encoding+"]");
		}
	}
    
    /**
     * return the mime type of a file, dont check extension
     * @param barr
     * @param defaultValue 
     * @return mime type of the file
     */
    public static String getMimeType(InputStream is, String defaultValue) {
    	try {
			return getMimeType(IOUtil.toBytesMax(is,1000), defaultValue);
		} catch (IOException e) {
			return defaultValue;
		}
    	
    	
    	/*try {
			return URLConnection.guessContentTypeFromStream(is);
		} catch (Throwable t) {
			return defaultValue;
		}*/
		
        /*try {
			return getMimeType(IOUtil.toBytesMax(is,1000), defaultValue);
		} catch (IOException e) {
			return defaultValue;
		}*/
    }
    
    
    /**
     * return the mime type of a file, dont check extension
     * @param barr
     * @return mime type of the file
     * @throws IOException 
     */
    public static String getMimeType(byte[] barr, String defaultValue) {
        
    	//String mt = getMimeType(new ByteArrayInputStream(barr), null);
    	//if(!StringUtil.isEmpty(mt,true)) return mt;
    	
    	PrintStream out = System.out;
        try {
        	System.setOut(new PrintStream(DevNullOutputStream.DEV_NULL_OUTPUT_STREAM));
            MagicMatch match = Magic.getMagicMatch(barr);
            return match.getMimeType();
        } 
        catch (Throwable t) {
			return defaultValue;
        }
        finally {
        	System.setOut(out);
        }
    }
    
    /**
     * @deprecated use instead <code>{@link #getWriter(Resource, Charset)}</code>
     * @param res
     * @param charset
     * @return
     * @throws IOException
     */
    public static Writer getWriter(Resource res, String charset) throws IOException {
    	return getWriter(res, CharsetUtil.toCharset(charset));
    }
    
 	public static Writer getWriter(Resource res, Charset charset) throws IOException {
 		OutputStream os=null;
 		try {
 			os=res.getOutputStream();
 		}
 		catch(IOException ioe) {
 			closeEL(os);
 			throw ioe;
 		}
 		return getWriter(os, charset);
   	 
 	}
 	
 	/**
 	 * @deprecated use instead <code>{@link #getWriter(Resource, Charset,boolean)}</code>
 	 * @param res
 	 * @param charset
 	 * @param append
 	 * @return
 	 * @throws IOException
 	 */
 	public static Writer getWriter(Resource res, String charset, boolean append) throws IOException {
 		return getWriter(res, CharsetUtil.toCharset(charset), append);
 	}
 	
 	public static Writer getWriter(Resource res, Charset charset, boolean append) throws IOException {
 		OutputStream os=null;
 		try {
 			os=res.getOutputStream(append);
 		}
 		catch(IOException ioe) {
 			closeEL(os);
 			throw ioe;
 		}
 		return getWriter(os, charset);
 	}
    
    /**
     * @deprecated use instead <code>{@link #getWriter(Resource, Charset)}</code> 
     * returns a Reader for the given File and charset (Automaticly check BOM Files)
     * @param file
     * @param charset
     * @return Reader
     * @throws IOException
     */
    public static Writer getWriter(File file, String charset) throws IOException {
    	OutputStream os=null;
 		try {
 			os=new FileOutputStream(file);
 		}
 		catch(IOException ioe) {
 			closeEL(os);
 			throw ioe;
 		}
 		return getWriter(os, charset);
   }
    
    /**
     * @deprecated use instead <code>{@link #getWriter(Resource, Charset, boolean)}</code> 
     * returns a Reader for the given File and charset (Automaticly check BOM Files)
     * @param file
     * @param charset
     * @return Reader
     * @throws IOException
     */
    public static Writer getWriter(File file, String charset, boolean append) throws IOException {
    	OutputStream os=null;
 		try {
 			os=new FileOutputStream(file,append);
 		}
 		catch(IOException ioe) {
 			closeEL(os);
 			throw ioe;
 		}
 		return getWriter(os, charset);
   }
     
    
    /**
     * @deprecated use instead <code>{@link #getWriter(OutputStream, Charset)}</code>
     * @param os
     * @param charset
     * @return
     * @throws IOException
     */
    public static Writer getWriter(OutputStream os, String charset) throws IOException {
    	return getWriter(os, CharsetUtil.toCharset(charset));
    }
    
    /**
     * returns a Reader for the given InputStream
     * @param is
     * @param charset
     * @return Reader
     * @throws IOException
     */
    public static Writer getWriter(OutputStream os, Charset charset) throws IOException {
   	 if(charset==null) charset=SystemUtil.getCharset();
        return new BufferedWriter(new OutputStreamWriter(os,charset));
    }

	public static String read(Reader reader, int size) throws IOException {
		return read(reader, new char[size]);
	}
	
	public static String read(Reader reader,char[] carr) throws IOException {
		int rst = reader.read(carr);
		if(rst==-1)return null;
		return new String(carr,0,rst);
	}
}