package basics.filesystem.serializer;

import java.io.File;
import java.io.IOException;
import basics.filesystem.file.LineReader;
import basics.filesystem.file.LineWriter;
import basics.unexpected.Failure;
import basics.utl.SUtl;
import basics.utl.SysUtl;

/**
 * Serialize and deserialize Objects into binary files.
 * @author kst
 */
public class SerializerFileFlat extends SerializerBase
{
protected LineWriter             out      = null;
protected LineReader             in       = null;
private boolean                isInUse  = false;
private static final String [] NL_SUBST = { "\n", "[<cr/>]" };
private static final String [] LF_SUBST = { "\r", "[<lf/>]" };

public SerializerFileFlat()
{
}

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

public synchronized boolean openForWriting(File f) //throws Exception
{
   if(f.exists())
   {
      try
      {
         f.delete();
      }
      catch(Exception e)
      {
         SysUtl.terror(e, "Could not delete " + f);
      }
   }
   try
   {
      out = new LineWriter(f);
      out.open(false);
      isInUse = true;
   }
   catch(Exception e)
   {
      SysUtl.terror(e, "Could not open " + f);
      return false;
   }
   return canWrite();
}

public synchronized boolean openForReading(File f) //throws Exception
{
   if(f.exists() && f.canRead())
   {
      try
      {
         in = new LineReader(f);
         in.open();
         isInUse = true;
      }
      catch(Exception e)
      {
         SysUtl.terror(e, "Could not open " + f);
         return false;
      }
   }
   return canRead();
}

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

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

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

public int readInt() throws IOException
{
   return SUtl.toInt(in.nextLine(), 0);
}

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

public long readLong() throws IOException
{
   return SUtl.toLong(in.nextLine(), 0);
}

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

public double readDouble() throws IOException
{
   return SUtl.toDouble(in.nextLine(), 0);
}

/**
 * Supports multiline storage: Linefeed and CR are replaced by Strings: [<ln/>] [<cr/>]
 * @return
 * @throws IOException
 */
public void write(String value) throws IOException
{
   value = SUtl.replaceAll(value, NL_SUBST[0], NL_SUBST[1]);
   value = SUtl.replaceAll(value, LF_SUBST[0], LF_SUBST[1]);
   out.write(value);
}

/**
 * Supports multiline storage: Linefeed and CR are replaced by Strings: [<ln/>] [<cr/>]
 * @return
 * @throws IOException
 */
public String readString() throws IOException
{
   String value = in.nextLine();
   value = SUtl.replaceAll(value, NL_SUBST[1], NL_SUBST[0]);
   value = SUtl.replaceAll(value, LF_SUBST[1], LF_SUBST[0]);
   return value;
}

/**
 * Skips a line, used to not read a comment in the storage.
 * @throws IOException
 */
public void skipLine() throws IOException
{
   in.nextLine();
}
}
