#include "libnazgul.h"
#include "ids.h"

/* prototypes des fonctions annexes à ne pas exporter */
int msgSpaceIdIntern(msgSpaceId dest,const msgSpaceId src );
int msgPoolDataIdIntern(msgSpaceId dest,const msgSpaceId src );
int msgPoolDataTabSemIdIntern(
	msgPoolSemId destSemId,const msgSpaceId externId);
/*
 * spaceId : identifiant externe de l'espace de msg
 * queueNb : nombre de files de messages
 * poolNb : nombre de pool de buffers
 * queueNbCar : tableau de caracteristiques des different pool
 */

msgSpace * msgSpaceCreate(
	msgSpaceId externId, 
	int queueNb, 
	int poolNb, 
	msgPool * poolInfos ){
  msgSpaceId nzgId;
  /* msgSpaceList mSList;  */
  int mSFd; // shm file descriptor
   int i;
  static int mSIdNum=-1;
  msgSpace * space;

  msgPoolDataTabId poolDataTabId;
  msgPoolData * poolDataTabAddr; 
  msgBufferInfoTabId bufferInfoTabId;
  msgPoolId poolId;
  sem_t * mSDataTabSemFd;

  mSIdNum++;
  space=NULL;
  /** recuperation de la liste des msgSpace **/
  /* (creation si elle n'existe pas */

  /** on créee le nouvel element **/
  printf("PAGESIZE : %d\n",(int)PAGESIZE);
  if (msgSpaceIdIntern(nzgId,externId) < 0){
	return NULL;
  }
  fprintf(stderr,"Creating msgSpace with id : %s\n",nzgId);
  mSFd=shm_open(
	  nzgId,
	  O_RDWR|O_CREAT|O_EXCL|O_TRUNC,
	  MSGSPACE_DEFAULT_MODE
	  );
  if (mSFd == -1 ) {
	NZG_ERROR("shm_open : msgSpace creation",nzgId);
	goto ERROR;
  }

  /* on redimentionne l'element */
  if (ftruncate(mSFd, sizeof(* space)) == -1){
	NZG_ERROR("ftruncate",nzgId);
	goto ERROR;
  }

  /* Map the memory object */
  space = mmap( 0, sizeof( *space ),
	  PROT_READ | PROT_WRITE,
	  MAP_SHARED, mSFd, 0 );
  if( space == MAP_FAILED ) {
	NZG_ERROR("mmap",nzgId);
	goto ERROR;
  }

  printf( "CREAT: msgSpace mapped to 0x%08x in %d\n", (int)space,(int)getpid());

  /* on ferme le descripteur du fichier */
  close(mSFd);

  /* on remplit la structure */
  strncpy(space->id,externId,MSGSPACE_ID_LEN);
  space->poolNb=poolNb;
  space->queueNb=queueNb;
  space->pid=getpid();
  msgPoolDataTabSemIdIntern(space->poolDataTabSemId,externId);
  /*  creation du poolData */
  msgPoolDataIdIntern(poolDataTabId,externId);
  strcpy(space->poolDataTabId,poolDataTabId);
  strcpy(space->externId,externId);

  mSDataTabSemFd=sem_open(space->poolDataTabSemId,
	  O_CREAT|O_EXCL,SEM_DEFAULT_MODE,0);
  if (mSDataTabSemFd == SEM_FAILED){ 
	NZG_ERROR("sem_open : creation de la ressource",
		space->poolDataTabSemId);
	goto ERROR; 
  } else {
	NZG_ERROR("sem_open : creation oki",
		space->poolDataTabSemId);
  }
  sem_close(mSDataTabSemFd);

  /*  attacher le tableau des msgPoolData */
  poolDataTabAddr=msgPoolDataTabCreate(space);
  if (poolDataTabAddr == NULL){
	NZG_ERROR("msgPoolDataTabCreate",space->poolDataTabId);
	goto ERROR;
  }

  for (i=0;i<poolNb;i++){
	/* Pour chacun des poolData
	 * - y écrire les informations passées en param
	 * - creer les zones mémoires de chacune des pool
	 */
	// creation d'une pool
	poolDataTabAddr[i].bufferNb=poolInfos[i].bufferNb;
	poolDataTabAddr[i].bufferSize=poolInfos[i].bufferSize;
	poolDataTabAddr[i].allocDispBuffer=0;

	if (msgBufferInfoTabIdIntern(bufferInfoTabId,externId,i) == -1){
	  fprintf( stderr, "msgBufferInfoTabId creation failed for id %s\n",
		  (char*)poolId );
	  return NULL;
	}	
	strcpy(poolDataTabAddr[i].bufferInfoTabId,bufferInfoTabId);
	printf("buffIfoTab %d name : %s\n",i,poolDataTabAddr[i].bufferInfoTabId);
	msgBufferInfoTabCreate(externId,poolDataTabAddr,i,poolInfos[i].bufferNb);

	if (msgPoolIdIntern(poolId,externId,i) == -1){
	  fprintf( stderr, "msgPoolId creation failed for id %s\n",
		  (char*)poolId );
	  return NULL;
	}
	strcpy(poolDataTabAddr[i].poolId,poolId);
	msgPoolCreate(externId,i,poolInfos[i].bufferNb,poolInfos[i].bufferSize);

  }

  /* on crée queueNb files de messages */
  printf("Creating queues:\n");
  for (i=0; i<queueNb;i++){
	printf("- queue %i...",i); fflush(stdout);
	if (msgQueueInit(space->externId,i) < 0){
	  printf("fail.\n");
	  NZG_ERROR("msgQueueInit : queue ?? for",space->externId);
	  goto ERROR;
	}
	printf("ok.\n");
  }
  msgPoolDataTabClose(space,poolDataTabAddr);
  /* on ajoute spaceId a la liste des msgSpace connus */
 msgSpaceListElemId listElemId;
//TODO: msgSpaceListInit();
 msgSpaceListLock(); 
 msgSpaceListElemCreate(listElemId,space);
  msgSpaceListAdd(listElemId);
 msgSpaceListUnlock(); 
  
  /* on renvoie un pointeur sur le bon spaceId */
 msgPoolDataTabUnlock(space);
  return space;
ERROR:
  return NULL;
}