/**
 * Copyright 2007 Michael Chen
 * Distributed under the GNU General Public License 2.0
 */

package com.xruby.runtime.builtin;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

import com.xruby.runtime.lang.RubyConstant;
import com.xruby.runtime.lang.RubyException;
import com.xruby.runtime.lang.RubyRuntime;
import com.xruby.runtime.lang.RubyValue;

class RubyIOFileExecutor implements RubyIOExecutor {

    private RandomAccessFile file_ = null;

    public RubyIOFileExecutor(String filename, String mode) {
        open(filename, mode);
    }

    private String translateMode(String mode) {
        if (mode.equals("w")) {
            return "rw";
        } else if (mode.equals("rb")) {
            return "r";
        } else if (mode.equals("r+")) {
            return "r";
        } else {
            return mode;
        }
    }

    private boolean open(String filename, String mode) {
        assert (null == file_);
        try {
            file_ = new RandomAccessFile(filename, translateMode(mode));
            if (mode.equals("w")) {
                file_.setLength(0);
            }
            return true;
        } catch (FileNotFoundException e) {
            return false;
        } catch (IOException e) {
            file_ = null;
            return false;
        }
    }

    public boolean eof() {
        try {
            return file_.length() == file_.getFilePointer();
        } catch (IOException e) {
            throw new RubyException(RubyRuntime.IOErrorClass, e.toString());
        }
    }

    public void close() {
        if (null != file_) {
            try {
                file_.close();
                file_ = null;
            } catch (IOException e) {
                // Do not care
            }
        }
    }

    public void flush() {
        try {
            file_.getChannel().force(false);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void print(String s) {
        if (null == file_) {
            throw new RubyException(RubyRuntime.IOErrorClass, "file is not opened");
        }

        try {
            file_.writeBytes(s);
        } catch (IOException e) {
            // FIXME: deal with the exception
        }
    }

    private String readsTheEntireContents() throws IOException {
        int size = (int) file_.length();// TODO converted long to int
        byte[] buffer = new byte[size];
        if (file_.read(buffer) < 0) {
            return "";
        } else {
            return new String(buffer);
        }
    }

    private String readUntilSeperator(String separator) throws IOException {
        // FIXME This is cheating, should read until separator
        String s = file_.readLine();
        if (null == s) {
            return null;
        } else {
            return s + "\n";
        }
    }

    public String gets(RubyValue separator) {
        if (null == file_) {
            throw new RubyException(RubyRuntime.IOErrorClass, "file is not opened");
        }

        try {
            if (RubyConstant.QNIL == separator) {
                return readsTheEntireContents();
            }

            if (!(separator instanceof RubyString)) {
                throw new RubyException(RubyRuntime.TypeErrorClass, "can't convert "
                        + separator.getRubyClass().getName() + " into String");
            }

            RubyString s = (RubyString) separator;

            return readUntilSeperator(s.toString());
        } catch (IOException e) {
            throw new RubyException(RubyRuntime.IOErrorClass, e.toString());
        }
    }

    public String read() {
        if (null == file_) {
            throw new RubyException(RubyRuntime.IOErrorClass, "file is not opened");
        }

        try {
            return readsTheEntireContents();
        } catch (IOException e) {
            throw new RubyException(RubyRuntime.IOErrorClass, e.toString());
        }
    }

    public String read(long length) {
        if (null == file_) {
            throw new RubyException(RubyRuntime.IOErrorClass, "file is not opened");
        }

        try {
            long size = file_.length();
            size = Math.min(length, size);
            byte[] buffer = new byte[(int) size];
            if (file_.read(buffer) < 0) {
                return null;
            } else {
                return new String(buffer);
            }
        } catch (IOException e) {
            throw new RubyException(RubyRuntime.IOErrorClass, e.toString());
        }
    }

    public String read(int length, int offset) {
        if (null == file_) {
            throw new RubyException(RubyRuntime.IOErrorClass, "file is not opened");
        }

        try {
            file_.seek(offset);
        } catch (IOException e) {
            throw new RubyException(RubyRuntime.IOErrorClass, e.toString());
        }

        return read(length);
    }

    public int write(String s) {
        print(s);
        return s.length();
    }

    public void truncate(int length) {
        try {
            file_.setLength(length);
        } catch (IOException e) {
            throw new RubyException(RubyRuntime.IOErrorClass, e.toString());
        }
    }

    public void seek(long pos) {
        try {
            file_.seek(pos);
        } catch (IOException e) {
            throw new RubyException(RubyRuntime.IOErrorClass, e.toString());
        }
    }
}

@@ -183,32 +183,53 @@
 io.IOException;%0A
+import java.io.File;%0A
 import java.io.R
@@ -722,16 +722,80 @@
 n %22rw%22;%0A
+        %7D else if (mode.equals(%22a%22)) %7B%0A            return %22rw%22;%0A
         
@@ -1062,16 +1062,76 @@
 file_);%0A
+%09%09File f = new File(filename);%0A%09%09long length =  f.length();%0A
         
@@ -1178,23 +1178,16 @@
 ssFile(f
-ilename
 , transl
@@ -1279,32 +1279,102 @@
 );%0A            %7D
+ else if (mode.equals(%22a%22)) %7B%0A                file_.seek(length);%0A%09%09%09%7D
 %0A            ret

support "a"