#ifndef TM_H_
#define TM_H_

#include <nand.h>
#include <req.h>
#include <defs.h>
#include <scsi_layer.h>

/******************************************/
/*                                                              Defines                                                                 */
/******************************************/
#define TM_PREPARE_TO_RECLAIM_REQ_MARKER ((req_t*)(IDX_EMPTY-1)) /* specifal marker of non-existent req, just to know that this chip is not really free, just waiting for reclaim req to be allocated*/
#define TM_REQ_GET_SPECIFIC(REQ) ((tm_specific_t*)((REQ)->specific))
/*****************************************************/
/* 						Defines												 			   */
/*****************************************************/
#define TM_OPEN_EUS    NAND_CHIP_COUNT
/*****************************************************/
/* 						Data structures												 */
/*****************************************************/
typedef struct tm_specific_st {
  cdb_t*     cdb;

  enum {
  	TM_INITIAL, //0
  	TM_ACQUIRE_LBA, //1
  	TM_ERASE_INITIAL, // 2
  	TM_LBA_INITIAL,// 3
  	TM_READ_LBA_TAKEN, //4
  	TM_LBA_TAKEN, //5
  	TM_WRITE_LBA_TAKEN, //6
    TM_NANDBUS_READY,// 7
    TM_NAND_WRITE_DONE,//8
    TM_WRITE_READY, //9

    TM_CHM_READ_READY,//10
    TM_CHM_READ_DONE, //11
    TM_CHIP_FOUND,//12
    TM_CHM_WRITE_READY, //13

    TM_RECLAIM_START, // 14
    TM_RECLAIM_NEXT_LBA,//15
    TM_RECLAIM_READ_READY, // 16
		TM_RECLAIM_NANDBUS_READY, // 17
		TM_RECLAIM_READ_DONE, // 18
		TM_RECLAIM_ERASE_READY, // 19
		TM_RECLAIM_ERASE_DONE,// 20
		TM_RECLAIM_DONE, // 21

		TM_CHM_FORWORD,//22
    TM_DONE,//23
    TM_TERMINATE// 24
  } state;

  uint32_t curr_lba;
  uint32_t page;
//  uint32_t last_known_written_page;

  req_t* pending_reclaim_req; /* is this write performed our of order (special case within reclamation)*/
  bool_t is_page_read;
  uint8_t spare[NAND_SPARE_SIZE];

  uint32_t rec_chip_idx;
  uint32_t chip_idx;
  /* pointers for list of requests of same lba*/
  req_t* lba_prev;
  req_t* lba_next;

  enum {
  	TM_ENQUEUE_REASON_NONE,
  	TM_ENQUEUE_REASON_NO_CHIP,
  	TM_ENQUEUE_REASON_LBA_TAKEN
  } enq_reason;

  bool_t ooo_read;
} tm_specific_t;

typedef struct tm_block_st{
	uint32_t address;
	uint32_t obs_count; /* # of obsolete sectors*/

	enum{
		TM_BLOCK_EMPTY, //0
		TM_BLOCK_PARTIAL, //1
		TM_BLOCK_FULL //2
	}state;
}tm_block;

typedef struct struct_tm{
  uint8_t bitmap[TM_BITMAP_SIZE];

  struct{
  	uint32_t address; /* physical address of erase unit*/
  	uint8_t  offset;  /* last programed page offset in unit*/
  	uint32_t blk_idx; /* block index in chip*/

    req_t*   current; /* current request handled to eu*/
//    uint32_t curr_lba; /* current lba that this chip can handle*/
    req_t* reclamation_in_progress; /*reclamation req in progress in this unit*/
    bool_t in_reclaim; /*has relevant chip entered reclaim mode*/
  }open_eu[TM_OPEN_EUS];

  tm_block block[TM_BLOCK_COUNT];

  /* struct access mutex*/
  pthread_mutex_t mutex;
  pthread_cond_t  cond;
  int  mutex_counter;

  /* general requests queue*/
	req_t* queue;

	/* deferred requests queue*/
  pthread_mutex_t defer_mutex;
  req_t* tmDeferred; /* cdb with no tmRequest*/

  /* reclamation fields*/
  struct{
  	int32_t  blk_idx;
  	uint32_t address; /*address of reclaimed block*/
		uint32_t offset; /*page offset until which we reclaimed so far */

		uint8_t buf[NAND_TOTAL_SIZE];
  } rec_eu[TM_OPEN_EUS];
  uint8_t last_chip_idx;

  list_t* handled_lba; /* reqs currently handling unique lba*/
  list_t* lba_pending; /*list of reqs pending for previous req of this lba to finish*/
  list_t* chip_pending; /*list of reqs pending for a chip to be free for writing*/
//  list_t* resource_pending;
} tm_t;
/******************************************/
/*     Prototypes    										  */
/******************************************/

void tmInit();

void tmAlloc(req_t* caller_req);

error_t tmRequest(req_t *req,
                  cdb_t* cdb,
                  uint32_t rec_chip_idx);

void tmHandler(req_t* req, void* response);

void tm_activate_former_lba_pending(req_t* req);

list_t* list_lookup(list_t** list, uint32_t lba);

uint32_t tm_get_free_chip_idx(req_t* req);

void tm_activate_former_chip_pending(req_t* req, uint32_t idx);
//bool_t
//tm_is_reclaim_or_with_pending(req_t* req);
//
//bool_t
//tm_is_with_pending_reclaim(req_t* req);
//
//void
//tm_debug_set_max_chips_full();

//void LOCK_TM_MUTEX();
//void UNLOCK_TM_MUTEX();
#endif /*TM_H_*/
