package commons.persistence;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import basics.filesystem.serializer.SerializerBase;
import basics.unexpected.Failure;
import commons.collections.Classification;
import commons.collections.HashList;
import commons.collections.ListOfIndexedSentences;
import commons.collections.ListOfSentences;
import commons.collections.MapMap;
import commons.collections.MapSetOfStrings;
import commons.collections.Pair;
import commons.collections.PairList;
import commons.collections.TermTable;
import commons.collections.TermValue;

/**
 * Serialize and deserialize complex objects, uses an underlying {@link BasicReadWrite}
 * implementation for binary or flat file writing.
 * @author ks
 */
public abstract class ObjectStoreBase extends PersistenceManager
{
public final boolean verbose = false;

public SerializerBase getSerializer()
{
   return serializer;
}

protected static SerializerBase serializer = null;


protected String getFileName(String base, String id, String state)
{
   return new File(base, id + "." + state).getAbsolutePath();
}

protected File getFile(String base, String id, String state)
{
   return new File(base, id + "." + state);
}

public Storable<?> load(Storable<?> object) throws IOException
{
   if(object == null)
      throw new Failure("Template Object is null!");
   return object.load(this);

}

public void store(Storable<?> object) throws IOException
{
   if(object == null)
      throw new Failure("Object is null!");
   object.save(this);

}

public void writeListOfClassifications(List<Classification> list) throws IOException
{
   serializer.write("#LOC");
   int size = list.size();
   serializer.write(size);
   for(int i = 0; i < size; i++)
      write(list.get(i));
}

public List<Classification> readClassificationList() throws IOException
{
   serializer.readString();
   int size = serializer.readInt();
   List<Classification> list = new ArrayList<Classification>();
   for(int i = 0; i < size; i++)
      list.add(readClassification());
   return list;
}

public void write(Classification c) throws IOException
{
   serializer.write("#CLASS");
   serializer.write(c.getId());
   serializer.write(c.getTermVector());
   serializer.write(c.getTermVectorMagnitude());
}

public Classification readClassification() throws IOException
{
   serializer.readString();
   Classification c = new Classification();
   c.setId(serializer.readString());
   c.setTermVector(serializer.readDoubleArray());
   c.setTermVectorMagnitude(serializer.readDouble());
   return c;
}

public void write(ListOfSentences los) throws IOException
{
   serializer.write("#LOS");
   serializer.write(los.size());
   for(List<String> l : los.getLists())
   {
      int n = l.size();
      serializer.write("#");
      serializer.write(n);
      for(String t : l)
         serializer.write(t);
   }
}

public void write(ListOfIndexedSentences los) throws IOException
{
   serializer.write("#ILOS");
   serializer.write(los.size());
   for(List<Integer> l : los.getLists())
   {
      int n = l.size();
      serializer.write("#");
      serializer.write(n);
      for(int t : l)
         serializer.write(t);
   }
}

public ListOfSentences readListOfSentences() throws IOException
{
   ListOfSentences los = new ListOfSentences();
   serializer.skipLine();
   int x = serializer.readInt();
   for(int i = 0; i < x; i++)
   {
      serializer.skipLine();
      List<String> list = new ArrayList<String>();
      int z = serializer.readInt();
      for(int j = 0; j < z; j++)
         list.add(serializer.readString());
      los.nextList(list);
   }
   return los;
}

public ListOfIndexedSentences readListOfIndexedSentences() throws IOException
{
   ListOfIndexedSentences los = new ListOfIndexedSentences();
   serializer.skipLine();
   int x = serializer.readInt();
   for(int i = 0; i < x; i++)
   {
      serializer.skipLine();
      List<Integer> list = new ArrayList<Integer>();
      int z = serializer.readInt();
      for(int j = 0; j < z; j++)
         list.add(serializer.readInt());
      los.nextList(list);
   }
   return los;
}

public void write(PairList list) throws IOException
{
   serializer.write("#LOP");
   serializer.write(list.size());
   for(Pair p : list.getList())
      write(p);
}

public PairList readPairList() throws IOException
{
   serializer.readString();
   PairList list = new PairList();
   int x = serializer.readInt();
   for(int i = 0; i < x; i++)
   {
      Pair p = readPair();
      list.add(p.getTerm1(), p.getTerm2(), p.getValue());
   }
   list.refreshIndex();
   return list;
}

public void write(Pair p) throws IOException
{
   serializer.write(p.getTerm1());
   serializer.write(p.getTerm2());
   serializer.write(p.getValue());
}

public Pair readPair() throws IOException
{
   Pair p = new Pair();
   p.setTerm1(serializer.readString());
   p.setTerm2(serializer.readString());
   p.setValue(serializer.readDouble());
   return p;
}

public void write(TermTable object) throws IOException
{
   serializer.write("#TT");
   serializer.write(object.size());
   for(Iterator<String> iter = object.keyIterator(); iter.hasNext();)
   {
      String k = iter.next();
      serializer.write(k);
      serializer.write(object.getValue(k));
   }
}

/**
 * Note: this output is not sorted.
 */
public TermTable readTermTable() throws IOException
{
   serializer.readString();
   TermTable tt = new TermTable();
   int x = serializer.readInt();
   for(int i = 0; i < x; i++)
      tt.add(serializer.readString(), serializer.readDouble());
   return tt;
}

public void write(TermValue term) throws IOException
{
   serializer.write(term.getTerm());
   serializer.write(term.getValue());
}

public TermValue readTerm() throws IOException
{
   TermValue t = new TermValue();
   t.setTerm(serializer.readString());
   t.setValue(serializer.readDouble());
   return t;
}

public void write(HashList list) throws IOException
{
   serializer.write("#HASHLIST");
   serializer.write(list.size());
   for(String t : list.getList())
      serializer.write(t);
}

public HashList readHashList() throws IOException
{
   serializer.readString();
   HashList list = new HashList();
   int x = serializer.readInt();
   for(int i = 0; i < x; i++)
      list.getOrAdd(serializer.readString());
   return list;
}

public void write(MapSetOfStrings ms) throws IOException
{
   serializer.write("#MAPSET");
   serializer.write(ms.size());
   if(ms.size() == 0)
      return;
   Iterator<String> iter = ms.keyIterator();
   while(iter.hasNext())
   {
      String ok = iter.next();
      Set<String> set = ms.get(ok);
      serializer.write(set.size());
      serializer.write(ok);
      Iterator<String> inner = set.iterator();
      while(inner.hasNext())
      {
         serializer.write(inner.next());
      }
   }
}

public MapSetOfStrings readMapSet() throws IOException
{
   serializer.readString();
   MapSetOfStrings ms = new MapSetOfStrings();
   int x = serializer.readInt();
   for(int i = 0; i < x; i++)
   {
      int z = serializer.readInt();
      if(z > 0)
      {
         String ok = serializer.readString();
         for(int j = 0; j < z; j++)
            ms.put(ok, serializer.readString());
      }
   }
   return ms;
}

public void write(MapMap<Double> data) throws IOException
{
   serializer.write("#MAPMAP");
   serializer.write(data.size());
   if(data.size() == 0)
      return;
   Iterator<String> iter = data.keyIterator();
   while(iter.hasNext())
   {
      String ok = iter.next();
      serializer.write(data.size(ok));
      serializer.write(ok);
      Iterator<String> inner = data.innerKeyIterator(ok);
      while(inner.hasNext())
      {
         String ik = inner.next();
         serializer.write(ik);
         double d = data.get(ok, ik);
         serializer.write(d);
      }
   }
}

public MapMap<Double> readMapMap() throws IOException
{
   MapMap<Double> data = new MapMap<Double>();
   serializer.skipLine();
   int x = serializer.readInt();
   for(int i = 0; i < x; i++)
   {
      int z = serializer.readInt();
      String ok = serializer.readString();
      for(int j = 0; j < z; j++)
      {
         String ik = serializer.readString();
         double d = serializer.readDouble();
         data.put(ok, ik, d);
      }
   }
   return data;
}

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

public double [] readDoubleArray() throws IOException
{
   return serializer.readDoubleArray();
}

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

public int [] readIntArray() throws IOException
{
   return serializer.readIntArray();
}

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

public long [] readLongArray() throws IOException
{
   return serializer.readLongArray();
}

public String readString() throws IOException
{
   return serializer.readString();
}

public List<String> readStringList() throws IOException
{
   return serializer.readStringList();
}

public void skipLine() throws IOException
{
   serializer.skipLine();
}

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

public void write(double [] array) throws IOException
{
   serializer.write(array);
}

public void write(int value) throws IOException
{
   serializer.write(value);
}

public void write(int [] array) throws IOException
{
   serializer.write(array);
}

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

public void write(long [] array) throws IOException
{
   serializer.write(array);
}

public void write(String value) throws IOException
{
   serializer.write(value);
}

public void writeListOfStrings(List<String> list) throws IOException
{
   serializer.writeListOfStrings(list);
}
}
