package basics.collections.index;

import java.io.IOException;

import basics.filesystem.serializer.Serializer;
import basics.filesystem.serializer.SerializerFileFlat;
import basics.unexpected.Failure;
import basics.utl.ObjectUtl;
import basics.utl.SUtl;
import basics.utl.SysUtl;

/**
 * Provides an index an a list of features.
 * @author ks
 *
 * @param <D>
 */
public class IndexListProvider<T extends Indexable> extends IndexList<T>
{
public static final String BADREAD  = "Failure reading, %";
private static final String BADROW   = "Failure reading row % of %, %";
public static final String BADWRITE = "Failure writing dRow % (%), %";
/**
 * The template hack is needed because java generics are not 
 * generic enough for: T t = new T();
 */
private T                   template = null;

public IndexListProvider(T template)
{
   this.template = template;
}

public void enshure(T xd, int i)
{
   xd._index = i;
   int pos = pkIndex.enshure(xd._key, i);
//   if(pos != i)
//      throw new Failure(SUtl.sprint("Duplicate key: '%', positions %, %", xd._key, i, pos));
   indexedList.add(xd);
}

@SuppressWarnings("unchecked")
public synchronized int load(Serializer serializer)
{
   int size = -1;
   try
   {
      size = serializer.readInt();
      for(int i = 0; i < size; i++)
      {
         T xd = (T)template.create();
         if(!xd.load(serializer))
            throw new Failure(SUtl.sprint(BADWRITE, i, size, ObjectUtl.getId(serializer)));
         else
         {
            xd._index = i;
            int pos = pkIndex.enshure(xd._key, i);
//            if(pos != i)
//               throw new Failure(SUtl.sprint("Duplicate key: '%', positions %, %", xd._key, i, pos));
            indexedList.add(xd);
         }
      }
   }
   catch(IOException e)
   {
      SysUtl.trace(BADREAD, ObjectUtl.getId(serializer));
      size = -1;
   }
   return size;
}

public synchronized int save(Serializer serializer)
{
   int size = indexedList.size();
   int saved = 0;
   try
   {
      serializer.write(size);
      for(T xd : indexedList)
      {
         if(!xd.save(serializer))
         {
            SysUtl.trace(BADROW, saved, xd, ObjectUtl.getId(serializer));
         }
         else
            saved++;
      }
   }
   catch(IOException e)
   {
      size = -1;
      throw new Failure(SUtl.sprint(BADREAD, ObjectUtl.getId(serializer)));
   }
   return size;
}

public static void unittest()
{
   Serializer s = new SerializerFileFlat();
   Indexable fd = null;
   //   IndexListProvider<MultiLang> f = new IndexListProvider<MultiLang>(new MultiLang(null,
   //      (String)null));
   //   f.set(new MultiLang("halllo", "de"));
   //   f.set(new MultiLang("hallo", "en"));
   //   f.set(new MultiLang("haus", "de"));
   //   f.set(new MultiLang("house", "en"));
   //   fd = f.get("hallo");
   //   Test.assertNotNull(fd, "missing hallo");
   //   Test.printout("hallo: % % %", fd._index, fd._key, fd.toString());
   //   fd = f.get("haus");
   //   Test.assertNotNull(fd, "missing haus");
   //   Test.printout("haus: % % %", fd._index, fd._key, fd.toString());
   //   fd = f.get("house");
   //   Test.assertNotNull(fd, "missing house");
   //   Test.printout("house: % % %", fd._index, fd._key, fd.toString());
   //   f.applyFunctor(new IndexableFunctor<MultiLang>()
   //   {
   //
   //      public MultiLang apply(MultiLang fd)
   //      {
   //         ((MultiLang)fd).add("gr");
   //         return fd;
   //      }
   //   });
   //   s.openForWriting(new File("test"));
   //   f.save(s);
   //   s.close();
   //   s.openForReading(new File("test"));
   //   f.load(s);
   //   s.close();
   //   fd = f.get("hallo");
   //   Test.assertNotNull(fd, "missing hallo");
   //   Test.printout("hallo: % % %", fd._index, fd._key, fd.toString());
   //   fd = f.get("haus");
   //   Test.assertNotNull(fd, "missing haus");
   //   Test.printout("haus: % % %", fd._index, fd._key, fd.toString());
   //   fd = f.get("house");
   //   Test.assertNotNull(fd, "missing house");
   //   Test.printout("house: % % %", fd._index, fd._key, fd.toString());
}
}
