#include <blocks.h>
#include <tm.h>
#include <chunks.h>
#include <ngssd.h>

extern int maintid;
extern int tids[NAND_CHIP_COUNT];
static char mode[10] = "a+";

extern uint32_t program[NAND_PAGE_COUNT];

static FILE* open_file(char* fname){
	return fopen(fname, mode);
}

static void close_file(FILE* file){
	fclose(file);
}

static char filename[10] = "blocks.c";

/******************************************/
extern ngssd_t ngssd;
req_t* baDeferred = 0;

void baInit() {}

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

/**
 *
 * @param chip_idx identifier of chip in calling module
 */
req_t* baRequest(handler_t notifier, uint32_t chip_idx, uint8_t caller_type) {
  req_t* req;
  req = (req_t*) malloc(sizeof(req_t));

  ba_specific_t* specific;
  specific  = (ba_specific_t*) malloc(sizeof(ba_specific_t));
  if (req == 0 || specific == 0) {
    if (req != 0)      free(req);
    if (specific != 0) free(specific);
    return 0;
  }

  req->handler    = baHandler;
  req->caller_req = 0;
  req->specific   = specific;
  req->next       = 0; // not in any list
  req->prev       = 0; // not in any list

  specific->chip_idx = chip_idx;
  specific->caller_type = caller_type;
  specific->state    = BA_INITIAL;
  specific->notifier = notifier;

  specific->cdb.cmd = SCSI_WRITE;
  specific->cdb.start_lba = IDX_EMPTY;
  specific->cdb.buf = specific->cdb_buf;

  ngssd_lock();
	ngssd.handled_counter+= 1; // counter update
	ngssd_unlock();

  baHandler(req,0);

  return req;
}

void baHandler(req_t* req, void* response) {
	ba_specific_t* specific = (ba_specific_t*) (req->specific);

	LOG("specific->state %u caller_type\n", specific->state, specific->caller_type);
  switch (specific->state) {
		case BA_INITIAL:
			if(specific->caller_type == BA_TYPE_TM){
				specific->state = BA_TM_READY;
				tmAlloc(req);
			}
			else if(specific->caller_type == BA_TYPE_CHM){
				specific->state = BA_CHM_READY;
				chmAlloc(req);
			}
			break;
		case BA_TM_READY:
			specific->state = BA_DONE;
			tmRequest((req_t*) response,&(specific->cdb), specific->chip_idx);
			break;
		case BA_CHM_READY:
			specific->state = BA_DONE;
			chmRequest((req_t*) response,CHM_RECLAIM,0,0, HINT_FLAG_NO);
			break;
		case BA_DONE:
			ngssd_lock();
			ngssd.handled_counter-= 1; // counter update
			ngssd_unlock();
			LOG("free specific\n");
			free(specific);
			free(req);
			LOG("free done\n");
			break;
		default:
			assert(0);
  }

}
