package basics.filesystem.serializer;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import basics.unexpected.Failure;
import basics.utl.SysUtl;

/**
 * Serialize and deserialize Objects into binary files.
 * @author kst
 */
public class SerializerFileBinary extends SerializerBase
{
private ObjectOutputStream out     = null;
private ObjectInputStream  in      = null;
private boolean            isInUse = false;

public boolean canRead()
{
   return in != null;
}

public boolean canWrite()
{
   return out != null;
}

public SerializerFileBinary()
{
}

public synchronized void close()
{
   if(isInUse)
   {
      if(out != null)
      {
         try
         {
            out.flush();
         }
         catch(IOException ioe)
         {
            throw new Failure(ioe, "Could not close file");
         }
         try
         {
            out.close();
            isInUse = false;
            out = null;
         }
         catch(IOException ioe)
         {
            throw new Failure(ioe, "Could not close file");
         }
      }
      else
         if(in != null)
         {
            try
            {
               in.close();
               isInUse = false;
               in = null;
            }
            catch(IOException ioe)
            {
               throw new Failure(ioe, "Could not close file");
            }
         }
   }
}

public synchronized boolean openForWriting(File f)
{
   if(f.exists())
   {
      try
      {
         f.delete();
      }
      catch(Exception e)
      {
         SysUtl.terror(null, "Can't delete old file (" + f + ").");
      }
   }
   try
   {
      out = new ObjectOutputStream(new FileOutputStream(f));
      SysUtl.trace("Writing " + f + " with " + out.toString());
      isInUse = true;
   }
   catch(Exception e)
   {
      SysUtl.terror(null, "Could not open " + f + ", " + e.getMessage());
      return false;
   }
   return canWrite();
}

public synchronized boolean openForReading(File f)
{
   if(f.exists() && f.canRead())
   {
      try
      {
         in = new ObjectInputStream(new FileInputStream(f));
         isInUse = true;
         SysUtl.trace("Reading " + f + " (" + f.length() + " Byte) with " + in.toString());
      }
      catch(Exception e)
      {
         SysUtl.terror(null, "Could not open " + f + ", " + e.getMessage());
         return false;
      }
   }
   return canRead();
}

/**
 * Note: this output is not sorted.
 */
// ///////////////////////////////////////////////////////////////////////////
public void write(int value) throws IOException
{
   out.writeInt(value);
}

public int readInt() throws IOException
{
   return in.readInt();
}

public void write(long value) throws IOException
{
   out.writeLong(value);
}

public long readLong() throws IOException
{
   return in.readLong();
}

public void write(double value) throws IOException
{
   out.writeDouble(value);
}

public double readDouble() throws IOException
{
   return in.readDouble();
}

public void write(String _value) throws IOException
{
   String value = _value == null ? "" : _value;
   out.writeInt(value.length());
   out.writeChars(value);
}

public String readString() throws IOException
{
   int size = in.readInt();
   StringBuilder str = new StringBuilder(size);
   for(int i = 0; i < size; i++)
      str.append(in.readChar());
   return str.toString();
}

public void skipLine() throws IOException
{
   int size = in.readInt();
   for(int i = 0; i < size; i++)
      in.readChar();
}
}
