#ifndef SORT_FILE_H
#define SORT_FILE_H

#include <stdint.h>
#include <iostream>
#include "file.h"
#include "slot.h"
#include "param.h"

using namespace std;
using namespace hierarchy_memory::sort_file;

namespace hierarchy_memory
{
  namespace sort_file
  {
    /*
     * Cicurlar file, sort by delay
     */

    template <class T>
    class Sort_File : public File<T>
    {
      // *****[ variables ]*****
    protected : uint32_t       ptr_read;  // pointer of the next slot to read
    protected : uint32_t       ptr_write; // pointer of the next slot to write
      
      // *****[ constructor ]*****
    public : Sort_File (param_t param) : File <T> (param.name,param.size)
      {
	
      };
      
      // *****[ destructor ]*****
    public : ~Sort_File ()
      {
      };
      
      // *****[ reset ]*****
      // Reset the file in the empty state
    public : void reset ()
      {
	ptr_read  = 0;
	ptr_write = 0;
	File <T>::nb_slot   = 0;
	//nb_slot   = 0;
      };
      
      // *****[ transition ]*****
      // Decrease the delay at all cycle
    public : void transition ()
      {
	for (uint32_t it = 0; it < File <T>::nb_slot; it ++)
	  {
	    uint32_t ptr = (ptr_read + it)%File <T>::size;
	    
	    if (File <T>::slot[ptr].delay != 0)
	      File <T>::slot[ptr] .delay --;
	  }
      }
      
      // *****[ read ]*****
      // return the n-eme slot.
      // (first = 0)
    public : slot_t<T> read (uint32_t num)
      {
	if (num >= File <T>::nb_slot)
	  {
	    cerr << "<Sort_File.read> {ERROR} can't read because : num (" << num << ") >= nb_slot (" << File <T>::nb_slot << ")" << endl;
	    exit(1);
	  }

	return File <T>::slot[(ptr_read + num)%File <T>::size];
      };
      
      // *****[ pop ]*****
      // read the file, and update the pointer
    public : T pop  ()
      {
	return pop (0);
      }

      // *****[ pop ]*****
      // read the file, and update the pointer
    public : T pop  (uint32_t num)
      {
	if (num >= File <T>::nb_slot)
	  {
	    cerr << "<Sort_File.pop> {ERROR} can't read because : num (" << num << ") >= nb_slot (" << File <T>::nb_slot << ")" << endl;
	    exit(1);
	  }

	T val = File <T>::slot [(ptr_read+num)%File <T>::size].data;
	
	// Reorganize the file

 	for (uint32_t it = 0; it < num; it ++)
	  {
	    uint32_t ptr      = (ptr_read + num - it   )%File <T>::size;
	    uint32_t ptr_next = (ptr-1)%File <T>::size;

	    File <T>::slot [ptr] = File <T>::slot [ptr_next];
	  }

	File <T>::nb_slot --;
	ptr_read = (ptr_read+1)%File <T>::size;
	
	return val;
      }
      
      // *****[ push ]*****
      // Push a new value (they must have a slot free)
      // Is sort by delay
    public : bool push (uint32_t delay, T val)
      {
	// If full -> quit
	if (File <T>::nb_slot == File <T>::size)
	  return false;
	
	uint32_t ptr = ptr_write;
	
	// Scan the fill to find the good position (keep the sort)
	for (uint32_t it = 0; it < File <T>::nb_slot; it ++)
	  {
	    uint32_t ptr_scan = (ptr-1)%File <T>::size;
	    
	    if (File <T>::slot[ptr_scan].delay <= delay)
	      break; //find
	    
	    // reformor the file
	    File <T>::slot [ptr] = File <T>::slot [ptr_scan];
	    ptr                  = ptr_scan;
	  }
	
	File <T>::slot [ptr] = slot_t <T> (delay,val);
	ptr_write            = (ptr_write+1)%File <T>::size; // update the pointer
	File <T>::nb_slot ++;
	
	return true;
      }

      // *****[ print ]*****
    public    : friend ostream& operator<< (ostream& output_stream, const Sort_File & x)
      {
	output_stream << "<" << x.name << ">" << endl;
	output_stream << " * ptr_read    : " << x.ptr_read  << endl;
	output_stream << " * ptr_write   : " << x.ptr_write << endl;
	output_stream << " * nb_slot     : " << x.nb_slot   << endl;
	output_stream << " * size        : " << x.size      << endl;
	
	for (uint32_t it = 0; it < x.nb_slot; it ++)
	  {
	    uint32_t ptr = (x.ptr_read+it)%x.size;
	    output_stream << x.slot [ptr] << endl;
	  }
	
	return output_stream;
      };

    };
    
  }; //sort_file
}; //hierarchy_memory
#endif //!SORT_FILE_H
  
