void shmem_barrier(int* PE_start, int* logPE_stride, int* PE_size, long* pSync)
{
#ifndef EPK_CSITE_INST 
  esd_enter(epk_shm_regid[EPK__SHMEM_BARRIER]);
#endif
  TRACE_OFF();
  pshmem_barrier(PE_start, logPE_stride, PE_size, pSync);
  TRACE_ON();
  esd_collexit(epk_shm_regid[EPK__SHMEM_BARRIER],
                ELG_NO_ID, epk_shmem_create_com(*PE_start, *logPE_stride, *PE_size), 0, 0);
}
void shmem_barrier_all(void)
{
#ifndef EPK_CSITE_INST 
  esd_enter(epk_shm_regid[EPK__SHMEM_BARRIER_ALL]);
#endif
  TRACE_OFF();
  pshmem_barrier_all();
  TRACE_ON();
  esd_collexit(epk_shm_regid[EPK__SHMEM_BARRIER_ALL],
                ELG_NO_ID, epk_shm_all_cid, 0, 0);
}
void barrier(void)
{
#ifndef EPK_CSITE_INST 
  esd_enter(epk_shm_regid[EPK__BARRIER]);
#endif
  TRACE_OFF();
  pbarrier();
  TRACE_ON();
  esd_collexit(epk_shm_regid[EPK__BARRIER],
               ELG_NO_ID, epk_shm_all_cid, 0, 0);
}
void shmem_finalize(void)
{
#ifndef EPK_CSITE_INST 
  esd_enter(epk_shm_regid[EPK__SHMEM_FINALIZE]);
#endif
  TRACE_OFF();
  pshmem_finalize();
  TRACE_ON();
  esd_collexit(epk_shm_regid[EPK__SHMEM_FINALIZE],
                ELG_NO_ID, epk_shm_all_cid, 0, 0);
}
void shmem_init(void)
{
  esd_open();
  epk_shm_register();

#ifndef EPK_CSITE_INST 
  esd_enter(epk_shm_regid[EPK__SHMEM_INIT]);
#endif
  TRACE_OFF();
  pshmem_init();
  TRACE_ON();

  epk_shmem_init();
  esd_collexit(epk_shm_regid[EPK__SHMEM_INIT],
               ELG_NO_ID, epk_shm_all_cid, 0, 0);
}
int main( int argc , char** argv ){ 
#ifdef DEBUG
	MEM_ON();
	TRACE_OFF();
#endif

	//total execution timer
	Timer totalTimer;
	totalTimer.start();


	std::cout<<"****************************************************************"<<std::endl;
	std::cout<<"*            OpenMP execution with "<<omp_get_max_threads()<<" threads                   *"<<std::endl;
	std::cout<<"****************************************************************"<<std::endl;

	std::cout<<"\n\n\n";



	std::vector<std::string> imageName;
	
	

	std::stringstream input(argv[4]);
	double factor;
	input >> factor;


	int succeded = 0;
	int failed = 0;

	std::string operation( argv[3] );
	//parallel code timer
	Timer parallelTimer;


	//how many images to run in parallel.Number of threads created for the program
        unsigned int parallelImages = omp_get_max_threads();
        //counter for total files for parallel iterations
        unsigned int counter = 0;
        //how many iterations to run in parallel
        unsigned int parallelIterations = parallelImages;
	


	if( GetDirFileNames ( argv[1] , imageName ) )
	
	try {
		parallelTimer.start();
		for( std::vector<std::string>::iterator it = imageName.begin() ; it < imageName.end() ; it += parallelImages ){
				
			counter += parallelImages;
                        parallelIterations = parallelImages;
                        if( counter > imageName.size() )
                                parallelIterations =  imageName.size() - ( counter - parallelImages );

			#pragma omp parallel for
			for( unsigned int i = 0 ; i < parallelIterations ; i++ ) {				

			
				std::cout<<(*(it + i))<<"\n";
				IMAGE::Image* oldImage = NULL;
				IMAGE::Image* newImage = NULL;
				std::string oldName  = argv[1] + (*(it + i));
				std::string newName  = argv[2] + (*(it + i));
				try{

					oldImage= IMAGE::Image::createInstance( oldName );
					newImage = IMAGE::Image::createInstance( newName ); 
				
					////////////////////
					try{
						oldImage->open( oldName, 'r' );
						newImage->open( newName , 'w' );
						oldImage->readImageRaster();
						newImage->raster.createRaster( oldImage->raster );
					
						//check which operation to do
						if( operation == REVERSE ){
	                                                IMAGE::PROCESS::reverseColor( newImage->raster );
        	                                }
						else if( operation == BRIGHTNESS ) {
							IMAGE::PROCESS::adjustBrightness( newImage->raster , atoi( argv[4] ));
						}
						else if( operation == CONTRAST ) {
							IMAGE::PROCESS::adjustContrast( newImage->raster , atoi( argv[4] ) );
						}
                        	                else if( operation == RGB2GREY ) {
                                	                IMAGE::FILTERS::convertRGB2GREY( newImage->raster , atoi( argv[4] ));
                                        	}
						else if( operation == RGB2BW ) {
							IMAGE::FILTERS::convertRGB2BW( newImage->raster );
						}
						else if( operation == RGB2SEPIA ) {
							IMAGE::FILTERS::convertRGB2SEPIA( newImage->raster );
						}
						else if( operation == BLUR ) {
							IMAGE::PROCESS::blurImage( newImage->raster , atoi(argv[4]) );
						}
						else if( operation == ROTATE ) {
							IMAGE::PROCESS::rotateImage( newImage->raster , argv[4] ) ;
						}
						else if( operation == ZOOM ) {
							IMAGE::PROCESS::zoomImage( newImage->raster , 1 , 1 , 400 , 300 );
						}
						else if( operation == SCALE ) {
							IMAGE::PROCESS::scaleImage( newImage->raster , factor );
						}
                        	                else {
                                	                std::cout<<"Not a valid operation \n";
                                        	        exit(0);
                                       	 	}





						newImage->writeRasterToImage();
						succeded++;

					}
					catch( IMAGE::file_io_failed& e ) {
						std::cout<<e.what()<<"\n";
						failed++;
					}
					catch ( IMAGE::image_format_error& e ) {
						std::cout<<e.what()<<"\n";
						failed++;
					}		
					catch( IMAGE::empty_image& e ){
						std::cout<<e.what()<<"\n";
						failed++;
					}	
					catch ( IMAGE::empty_raster& e ) {
						std::cout<<e.what()<<"\n";
						failed++;
					}
				

						oldImage->close();
						newImage->close();
						delete oldImage;
						delete newImage;

					
			
				}
			catch( IMAGE::not_supported_format& e ) {
				std::cout<<e.what()<<"\n";
				failed++;
			}
			
		}//end of omp_parallel_for


		}//end of for
		
	}
	catch( IMAGE::bad_alloc& e ){
		std::cout<<e.what()<<std::endl;
		std::cout<<"Exiting program...\n";
		exit(1);

	}
	catch(...){
		std::cout<<"cought unexpected exception...\n";
		std::cout<<"Exitig program...\n";
		exit(1);
	}



        totalTimer.stop();
        parallelTimer.stop();


	//final output         //////////////////////////////////////////////////////////////

        std::cout<<"\n\n\n";
        std::cout<<"*************************************************************"<<std::endl;
        std::cout<<"*                          Results                          *"<<std::endl;

        std::cout<<"* total files      :  "<<imageName.size()<<"                                     *"<<std::endl;
        std::cout<<"* Succeded images  :  "<<succeded<<"                                     *"<<std::endl;
        std::cout<<"* Failed images    :  "<<failed<<"                                     *"<<std::endl;


        std::cout<<"*                                                           *"<<std::endl;
        std::cout<<"* Total execution time             :  "<<totalTimer.getReal()<<" sec          *"<<std::endl;
        std::cout<<"* Parallel partial execution time  :  "<<parallelTimer.getReal()<<" sec          *"<<std::endl;

        std::cout<<"*                                                           *"<<std::endl;
        std::cout<<"*                        END OF PROGRAM                     *"<<std::endl;
        std::cout<<"*************************************************************"<<std::endl;


	///////////////////////////////////////////////////////////////////////////////////////


#ifdef DEBUG
	MEM_OFF();
#endif


	return 0;
}