/****************************************************************************
 * Name          : cpsv_test_sync_app_process
 *
 * Description   : This is the function which is given as the input to the
 *                 Application task.
 *
 * Arguments     : info  - This is the information which is passed during
 *                         spawing Application task.
 *
 * Return Values : None.
 *
 * Notes         : None.
 *****************************************************************************/
void cpsv_test_sync_app_process(void *info)
{
   SaCkptHandleT ckptHandle;
   SaCkptCheckpointHandleT  checkpointHandle;
   SaCkptCallbacksT callbk;
   SaVersionT version;
   SaNameT ckptName;
   SaAisErrorT rc;
   SaCkptCheckpointCreationAttributesT ckptCreateAttr;
   SaCkptCheckpointOpenFlagsT ckptOpenFlags;
   SaCkptSectionCreationAttributesT sectionCreationAttributes;
   SaCkptIOVectorElementT writeVector, readVector;
   SaUint32T erroneousVectorIndex;
   void *initialData = "Default data in the section";
   unsigned char read_buff[100] = {0};
   SaTimeT timeout = 1000000000;
   unsigned int  temp_var = (unsigned int)(long)info; 


   memset(&ckptName, 0, 255);
   ckptName.length = strlen(DEMO_CKPT_NAME);
   memcpy(ckptName.value,DEMO_CKPT_NAME,strlen(DEMO_CKPT_NAME));

   callbk.saCkptCheckpointOpenCallback = AppCkptOpenCallback;
   callbk.saCkptCheckpointSynchronizeCallback = AppCkptSyncCallback;
   version.releaseCode= 'B';
   version.majorVersion = 2;
   version.minorVersion = 2;
   
   printf("*******************************************************************\n");
   printf("Demonstrating Checkpoint Service Usage with a collocated Checkpoint \n");
   printf("*******************************************************************\n");
   sleep(2);

   printf("Initialising With Checkpoint Service....\n");
   rc = saCkptInitialize(&ckptHandle,&callbk,&version);
   if(rc == SA_AIS_OK)
      printf("PASSED \n");
   else
      printf("Failed \n");

   ckptCreateAttr.creationFlags = SA_CKPT_CHECKPOINT_COLLOCATED|SA_CKPT_WR_ACTIVE_REPLICA;
   ckptCreateAttr.checkpointSize = 1024;
   ckptCreateAttr.retentionDuration= 100000;
   ckptCreateAttr.maxSections= 2;
   ckptCreateAttr.maxSectionSize = 700;
   ckptCreateAttr.maxSectionIdSize = 4;

   ckptOpenFlags = SA_CKPT_CHECKPOINT_CREATE|SA_CKPT_CHECKPOINT_READ|SA_CKPT_CHECKPOINT_WRITE;
   printf("Opening Collocated Checkpoint = %s with create flags....\n",ckptName.value);
   rc = saCkptCheckpointOpen(ckptHandle,&ckptName,&ckptCreateAttr,ckptOpenFlags,timeout,&checkpointHandle);
   if(rc == SA_AIS_OK)
      printf("PASSED \n");
   else
      printf("Failed \n");


   
   if(temp_var == 1)
   {
 
      printf("Setting the Active Replica for my checkpoint ....\t");
      rc = saCkptActiveReplicaSet(checkpointHandle);
      if(rc == SA_AIS_OK)
         printf("PASSED \n");
      else
         printf("Failed \n");
    

   sectionCreationAttributes.sectionId = (SaCkptSectionIdT*) malloc(sizeof \
                                (SaCkptSectionIdT));
   sectionCreationAttributes.sectionId->id = (unsigned char *)"11";
   sectionCreationAttributes.sectionId->idLen = 2;
   sectionCreationAttributes.expirationTime = 3600000000000ll;   /* One Hour */

   printf("Created Section ....\t");
   rc = saCkptSectionCreate(checkpointHandle,&sectionCreationAttributes,initialData,28);
   if(rc == SA_AIS_OK)
      printf("PASSED \n");
   else
      printf("Failed \n");

  
      writeVector.sectionId.id = (unsigned char *)"11";
      writeVector.sectionId.idLen = 2;
      writeVector.dataBuffer = "The Checkpoint Service provides a facility for processes to store checkpoint data";
      writeVector.dataSize = strlen(writeVector.dataBuffer);
      writeVector.dataOffset = 0;
      writeVector.readSize = 0;

      printf("Writing to Checkpoint %s ....\n",DEMO_CKPT_NAME);
      printf("Section-Id = %s ....\n",writeVector.sectionId.id);
      printf("CheckpointData being written = \"%s\"\n",(char *)writeVector.dataBuffer);
      printf("DataOffset = %llu ....\n",writeVector.dataOffset);
      rc = saCkptCheckpointWrite(checkpointHandle,&writeVector,1,&erroneousVectorIndex);
      if(rc == SA_AIS_OK)
         printf("PASSED \n");
      else
         printf("Failed \n");
      sleep(1); 

      printf("Press <Enter> key to continue...\n");
      getchar();
    }
    else
    {  
       sleep(4);
       readVector.sectionId.id = (unsigned char *)"11";
       readVector.sectionId.idLen = 2;
       readVector.dataBuffer = read_buff;
       readVector.dataSize = 90;
       readVector.dataOffset = 0;                                                                                                                                                                 
       printf("Waiting to Read from Checkpoint %s....\n",DEMO_CKPT_NAME);
       printf("Press <Enter> key to continue...\n");
       getchar();	
       rc = saCkptCheckpointRead(checkpointHandle,&readVector,1,&erroneousVectorIndex);
       printf("Checkpoint Data Read = \"%s\"\n",(char *)readVector.dataBuffer);
       if(rc == SA_AIS_OK)
          printf("PASSED \n");
       else
          printf("Failed \n");   
   }
   printf("Synchronizing My Checkpoint being called ....\n");
   rc = saCkptCheckpointSynchronize(checkpointHandle,timeout);
   if(rc == SA_AIS_OK)
      printf("PASSED \n");
   else
      printf("Failed \n");
                                             
   if(temp_var==1)
   {
      printf("Unlink My Checkpoint ....\t");
      rc = saCkptCheckpointUnlink(ckptHandle,&ckptName);
      if(rc == SA_AIS_OK)
         printf("PASSED \n");
      else
         printf("Failed \n");
   }
   printf("Ckpt Closed ....\t");
   rc = saCkptCheckpointClose(checkpointHandle);
   if(rc == SA_AIS_OK)
      printf("PASSED \n");
   else
      printf("Failed \n");
                                                                                                                                                                      

   printf("Ckpt Finalize being called ....\t");
   rc = saCkptFinalize(ckptHandle);
   if(rc == SA_AIS_OK)
      printf("PASSED \n");
   else
      printf("Failed \n");
                                                                                                                                                                      
   sleep(2);
  return;
}
static ClRcT checkpoint_initialize()
{
	SaAisErrorT rc = SA_AIS_OK;
	SaVersionT  ckpt_version = {'B', 1, 1};
	SaNameT     ckpt_name = { strlen(CKPT_NAME), CKPT_NAME };
	SaUint32T   seq_no;
	SaCkptCheckpointCreationAttributesT create_atts = {
		.creationFlags     = SA_CKPT_WR_ACTIVE_REPLICA_WEAK | SA_CKPT_CHECKPOINT_COLLOCATED,
		.checkpointSize    = sizeof(SaUint32T),
		.retentionDuration = (SaTimeT)0, 
		.maxSections       = 2, // default section, plus section we create
		.maxSectionSize    = sizeof(SaSizeT),
		.maxSectionIdSize  = (SaSizeT)64
	};

	SaCkptSectionCreationAttributesT section_atts = {
		.sectionId = &ckpt_sid,
		.expirationTime = SA_TIME_END
	};

	clprintf(CL_LOG_SEV_INFO,"%s: checkpoint_initialize\n", appname);
	/* Initialize checkpointing service instance */
	rc = saCkptInitialize(&ckpt_svc_handle, /* Checkpoint service handle */
			NULL,		    /* Optional callbacks table */
			&ckpt_version);   /* Required verison number */
	if (rc != SA_AIS_OK)
	{
		clprintf(CL_LOG_SEV_ERROR,"%s: ERROR: Failed to initialize checkpoint service\n", appname);
		return rc;
	}
	clprintf(CL_LOG_SEV_INFO,"%s: Checkpoint service initialized (handle=0x%x)\n", appname,(unsigned int) ckpt_svc_handle);

	//
	// Create the checkpoint for read and write.  If we fail to open it
	// then open it without CREATE.  The retry loop is to deal with the
	// possibility that multiple processes might all come along here
	// and fail to open the checkpoint because it hasn't been created
	// yet and then they all try to create the checkpoint.  All but
	// the first would fail.  This retry allows all the rest of the
	// processes to come through and open without CREATE
	// TODO: change it to a straight retry loop where we start off with
	// mode = (CL_CKPT_CHECKPOINT_READ | CL_CKPT_CHECKPOINT_WRITE)
	// and on each iteration of the loop we xor in
	// CL_CKPT_CHECKPOINT_CREATE.  That should let us do the same thing
	// but without the duplication of the clCkptCheckpointOpen call
	rc = saCkptCheckpointOpen(ckpt_svc_handle,      // Service handle
			&ckpt_name,         // Checkpoint name
			&create_atts,       // Optional creation attr.
			(SA_CKPT_CHECKPOINT_READ |
			 SA_CKPT_CHECKPOINT_WRITE |
			 SA_CKPT_CHECKPOINT_CREATE),
			(SaTimeT)-1,        // No timeout
			&ckpt_handle);      // Checkpoint handle
	if (rc != SA_AIS_OK)
	{
		clprintf(CL_LOG_SEV_ERROR,"%s: ERROR: Failed [0x%x] to open checkpoint\n", appname, rc);
		(void)saCkptFinalize(ckpt_svc_handle);
		return rc;
	}
	clprintf(CL_LOG_SEV_INFO,"%s: Checkpoint opened (handle=0x%x)\n", appname, (unsigned int) ckpt_handle);

	/*
	 * Try to create a section so that updates can operate by overwriting
	 * the section over and over again.
	 * If subsequent processes come through here, they will fail to create
	 * the section.  That is OK, even though it will cause an error message
	 * If the section create fails because the section is already there, then
	 * read the sequence number
	 */
	// Put data in network byte order
	seq_no = htonl(seq);

	// Creating the section
	checkpoint_replica_activate();
	rc = saCkptSectionCreate(ckpt_handle,           // Checkpoint handle
			&section_atts,         // Section attributes
			(SaUint8T*)&seq_no,    // Initial data
			(SaSizeT)sizeof(seq_no)); // Size of data
	if (rc != SA_AIS_OK && rc != SA_AIS_ERR_EXIST)
	{
		clprintf(CL_LOG_SEV_ERROR,"%s: ERROR: Failed [0x %x] to create checkpoint section\n", appname, rc);
		(void)saCkptCheckpointClose(ckpt_handle);
		(void)saCkptFinalize(ckpt_svc_handle);
		return rc;
	}
	else if (rc != SA_AIS_OK && rc == SA_AIS_ERR_EXIST)
	{
		rc = checkpoint_read_seq(&seq);
		if (rc != SA_AIS_OK)
		{
			clprintf(CL_LOG_SEV_ERROR,"%s: ERROR: Failed [0x%x] to read checkpoint section\n", appname, rc);
			(void)saCkptCheckpointClose(ckpt_handle);
			(void)saCkptFinalize(ckpt_svc_handle);
			return rc;
		}
	}
	else
	{
		clprintf(CL_LOG_SEV_INFO,"%s: Section created\n", appname);
	}
	/* Open checkpoint for read to write depending on input argument */

	return rc;
}

static SaAisErrorT checkpoint_finalize(void)
{
    SaAisErrorT rc;

    rc = saCkptCheckpointClose(ckpt_handle);
    if (rc != SA_AIS_OK)
    {
        clprintf(CL_LOG_SEV_ERROR,"%s: failed: [0x%x] to close checkpoint handle %d\n", appname, rc, (unsigned int) ckpt_handle);
    }
    rc = saCkptFinalize(ckpt_svc_handle);
    if (rc != SA_AIS_OK)
    {
        clprintf(CL_LOG_SEV_ERROR,"%s: failed: [0x%x] to finalize checkpoint\n", appname, rc);
    }
    return SA_AIS_OK;
}