/* sxr -- Scala X-Ray
 * Copyright 2009 Mark Harrah
 */

package sxr

import java.io.{FileOutputStream, InputStream, OutputStream}
import java.io.{BufferedReader, BufferedWriter, File, FileReader, FileWriter}

/** A collection of utilities for I/O*/
object object sxr.FileUtilFileUtil
{
	/** Managed resource operation.*/
	def (java.io.File)((java.io.BufferedReader) => Unit)UnitwithReader(java.io.Filesource: java.io.FileFile)((java.io.BufferedReader) => Unitf: BufferedReader => Unit)
	{
		val java.io.BufferedReaderinput = (java.io.Reader)java.io.BufferedReadernew java.io.BufferedReaderBufferedReader((java.io.File)java.io.FileReadernew java.io.FileReaderFileReader(java.io.Filesource))
		try { (java.io.BufferedReader)Unitf(java.io.BufferedReaderinput) }
		finally { java.io.BufferedReaderinput.()Unitclose() }
	}
	/** Managed resource operation.*/
	def (java.io.File)((java.io.BufferedWriter) => Unit)UnitwithWriter(java.io.Filetarget: java.io.FileFile)((java.io.BufferedWriter) => Unitf: BufferedWriter => Unit)
	{
		java.io.Filetarget.()java.io.FilegetParentFile.()Booleanmkdirs()
		import java.io.{BufferedWriter, FileWriter}
		val java.io.BufferedWriteroutput = java.io.BufferedWriternew java.io.BufferedWriterBufferedWriter((java.io.File)java.io.FileWriternew java.io.FileWriterFileWriter(java.io.Filetarget))
		try { (java.io.BufferedWriter)Unitf(java.io.BufferedWriteroutput) }
		finally { java.io.BufferedWriteroutput.()Unitclose() }
	}
	/** Get the number of common path components from the root.*/
	private def [S](Array[S],Array[S])IntcommonPrefix[>: Nothing <: AnyS](Array[S]a: Array[S]Array[S], Array[S]b: Array[S]Array[S]): IntInt =
	{
		def (Int)Intcommon(Intcount: IntInt): IntInt =
		{
			Intif(Intcount (Int)Boolean>= Array[S]a.=> Intlength (Boolean)Boolean|| Intcount (Int)Boolean>= Array[S]b.=> Intlength (Boolean)Boolean|| (Int)Sa(Intcount) (Any)Boolean!= (Int)Sb(Intcount))
				Intcount
			else
				(Int)Intcommon(Intcount(Int)Int+Int(1)1)
		}
		(Int)Intcommon(Int(0)0)
	}
	/** Converts the given file to an array of path component strings. */
	private def (java.io.File)Array[String]toPathArray(java.io.Filefile: java.io.FileFile): Array[String]Array[String] =
	{
		def (java.io.File,List[String])List[String]toPathList(java.io.Filef: java.io.FileFile, List[String]current: List[String]List[String]): List[String]List[String] =
		{
			List[String]if(java.io.Filef (AnyRef)Boolean== Null(null)null)
				List[String]current
			else
				(java.io.File,List[String])List[String]toPathList(java.io.Filef.()java.io.FilegetParentFile, java.io.Filef.()java.lang.StringgetName (String)List[String]:: List[String]current)
		}
		(java.io.File,List[String])List[String]toPathList(java.io.Filefile.()java.io.FilegetCanonicalFile, object NilNil).Array[String]toArray
	}
	/** Creates a relative path from 'fromFile' to 'toFile' (for use in an 'href' attribute).*/
	def (java.io.File,java.io.File)StringrelativePath(java.io.FilefromFile: java.io.FileFile, java.io.FiletoFile: java.io.FileFile): StringString =
	{
		val Array[String]fromPath = (java.io.File)Array[String]toPathArray(java.io.FilefromFile)
		val Array[String]toPath = (java.io.File)Array[String]toPathArray(java.io.FiletoFile)
		val IntcommonLength = (Array[String],Array[String])IntcommonPrefix(Array[String]fromPath, Array[String]toPath)
		val Array.Projection[String]relativeTo = Array[String]toPath.(Int)Array.Projection[String]drop(IntcommonLength)
		val IntparentsToCommon = (Array[String]fromPath.=> Intlength (Int)Int- IntcommonLength (Int)Int- Int(1)1)
		(Boolean)Unitrequire(IntparentsToCommon (Int)Boolean>= Int(0)0)
		val Stringup = implicit scala.Predef.stringWrapper : (String)scala.runtime.RichString"../" (Int)String* IntparentsToCommon
		Array.Projection[String]relativeTo.(String,String,String)StringmkString(Stringup, java.lang.String("/")"/", java.lang.String("")"")
	}
	
	/** Copies the 'resource' to be found on the classpath to the file 'to'.*/
	def (String,java.io.File)UnitwriteResource(Stringresource: StringString, java.io.Fileto: java.io.FileFile)
	{
		val java.io.InputStreamsource = ()java.lang.Class[_ <: java.lang.Object]getClass.(java.lang.String)java.io.InputStreamgetResourceAsStream(Stringresource)
		try { (java.io.InputStream,java.io.File)Unitwrite(java.io.InputStreamsource, java.io.Fileto) }
		finally { java.io.InputStreamsource.()Unitclose() }
	}
	/** Writes the 'input' stream to the file 'to'.*/
	private def (java.io.InputStream,java.io.File)Unitwrite(java.io.InputStreaminput: java.io.InputStreamInputStream, java.io.Fileto: java.io.FileFile)
	{
		val java.io.FileOutputStreamout = (java.io.File)java.io.FileOutputStreamnew java.io.FileOutputStreamFileOutputStream(java.io.Fileto)
		try { (java.io.InputStream,java.io.OutputStream)Unittransfer(java.io.InputStreaminput, java.io.FileOutputStreamout) }
		finally { java.io.FileOutputStreamout.()Unitclose() }
	}
	/** Copies all bytes from the 'input' stream to the 'output' strem. */
	private def (java.io.InputStream,java.io.OutputStream)Unittransfer(java.io.InputStreaminput: java.io.InputStreamInputStream, java.io.OutputStreamout: java.io.OutputStreamOutputStream)
	{
		val Array[Byte]buffer = Array[Byte]new Array[Byte]Array[Byte](Int(8192)8192)
		def ()Unittransfer()
		{
			val Intread = java.io.InputStreaminput.(Array[Byte])Intread(Array[Byte]buffer)
			Unitif(Intread (Int)Boolean>= Int(0)0)
			{
				java.io.OutputStreamout.(Array[Byte],Int,Int)Unitwrite(Array[Byte]buffer, Int(0)0, Intread)
				()Unittransfer()
			}
		}
		()Unittransfer()
	}
	/** Relativies the path of the given file against the given base file.*/
	def (java.io.File,java.io.File)Option[String]relativize(java.io.FilebaseFile: java.io.FileFile, java.io.Filefile: java.io.FileFile): Option[String]Option[String] =
	{
		val java.lang.StringpathString = java.io.Filefile.()java.lang.StringgetCanonicalPath
		(java.io.File)Option[String]baseFileString(java.io.FilebaseFile) ((String) => Option[String])Option[String]flatMap { StringbaseString =>
			Option[String]if(java.lang.StringpathString.(java.lang.String)BooleanstartsWith(StringbaseString))
				(java.lang.String)Some[java.lang.String]Some(java.lang.StringpathString.(Int)java.lang.Stringsubstring(StringbaseString.()Intlength))
			else
				object NoneNone
		}
	}
	// used by relativize
	private def (java.io.File)Option[String]baseFileString(java.io.FilebaseFile: java.io.FileFile): Option[String]Option[String] =
	{
		Option[String]if(java.io.FilebaseFile.()BooleanisDirectory)
		{
			val java.lang.Stringcp = java.io.FilebaseFile.()java.lang.StringgetCanonicalPath
			(Boolean)Unitassert(java.lang.Stringcp.()Intlength (Int)Boolean> Int(0)0)
			Option[String]if(java.lang.Stringcp.(Int)CharcharAt(java.lang.Stringcp.()Intlength (Int)Int- Int(1)1) (Char)Boolean== object java.io.FileFile.CharseparatorChar)
				(java.lang.String)Some[java.lang.String]Some(java.lang.Stringcp)
			else
				(java.lang.String)Some[java.lang.String]Some(java.lang.Stringcp (Any)java.lang.String+ object java.io.FileFile.CharseparatorChar)
		}
		else
			object NoneNone
	}
}