/*
 * Copyright 2013 Yuichiro Moriguchi
 *
 * Licensed 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.
 */
package net.morilib.sh.file;

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.io.PrintStream;

import net.morilib.sh.ShFile;
import net.morilib.sh.ShFileSystem;
import net.morilib.sh.ShStat;
import net.morilib.sh.misc.OSInfo;
import net.morilib.sh.misc.FileTypeUtils;

public abstract class ShRealFile implements ShFile {

	/**
	 * 
	 */
	protected ShFileSystem filesystem;

	/**
	 * 
	 */
	protected String virtualpath;

	/**
	 * 
	 */
	protected File file;

	/**
	 * 
	 * @param fs
	 * @param virtualpath
	 * @param file
	 */
	public ShRealFile(ShFileSystem fs, String virtualpath, File file) {
		this.filesystem  = fs;
		this.virtualpath = virtualpath;
		this.file = file;
	}

	public InputStream getInputStream() throws IOException {
		return new FileInputStream(file);
	}

	public String getName() {
		return file.getName();
	}

	public PrintStream getPrintStream(boolean append) {
		try {
			return new PrintStream(new FileOutputStream(file, append));
		} catch (FileNotFoundException e) {
			return null;
		}
	}

	public boolean isDirectory() {
		return file.isDirectory();
	}

	public boolean isExecutable() {
		InputStream ins = null;

		if(OSInfo.OS.isUNIX()) {
			return file.canExecute();
		} else if(file.isDirectory()) {
			return true;
		} else if(file.isFile()) {
			try {
				return FileTypeUtils.parseShebang(ins) != null;
			} catch(IOException e) {
				return false;
			} finally {
				try {
					if(ins != null)  ins.close();
				} catch(IOException e) {
					return false;
				}
			}
		} else {
			return false;
		}
	}

	public boolean isExist() {
		return file.exists();
	}

	public boolean isFile() {
		return file.isFile();
	}

	public long getLastModified() {
		return file.lastModified();
	}

	public boolean isReadable() {
		return file.canRead();
	}

	public boolean isWritable() {
		return file.canWrite();
	}

	/* (non-Javadoc)
	 * @see net.morilib.sh.ShFile#isHidden()
	 */
	public boolean isHidden() {
		return file.isHidden();
	}

	public boolean isZeroFile() {
		return file.length() == 0;
	}

	public ShFile toAbsolute() {
		if(virtualpath.length() > 0 && virtualpath.charAt(0) == '/') {
			return this;
		} else {
			return filesystem.getFile(
					filesystem.getCurrentDirectory().toString(),
					virtualpath);
		}
	}

	public boolean mkdir() {
		return file.mkdir();
	}

	public boolean renameTo(ShFile f) {
		if(f instanceof ShUnixRealFile) {
			file.renameTo(((ShRealFile)f).file);
			return true;
		} else {
			return false;
		}
	}

	public void setLastModified(long time) {
		file.setLastModified(time);
	}

	public boolean rmdir() {
		return file.isDirectory() && file.delete();
	}

	public boolean deleteFile() {
		return file.isFile() && file.delete();
	}

	public ShStat getStat() {
		ShStat r = new ShStat();
		int f = 0;

		r.setFilename(virtualpath);
		r.setMtime(file.lastModified());
		r.setSize(file.length());
		f |= isDirectory()  ? ShStat.DIRECTORY : 0;
		f |= isExecutable() ? ShStat.EXECUTABLE : 0;
		f |= isWritable()   ? ShStat.WRITABLE : 0;
		f |= isReadable()   ? ShStat.READABLE : 0;
		r.setFlags(f);
		return r;
	}

	public String toString() {
		return virtualpath;
	}

}
