#include "queue.hpp"

queue::queue()
{
	m_mode = QUEUE_MODE_RECV;
	m_filename = NULL;
	m_mqd = -1;
	memset( &m_msg, 0, sizeof(m_msg) );
}

queue::~queue()
{
	close();
	release_filename();
}

void queue::release_filename( void )
{
	if( m_filename )
	{
		free( m_filename );
		m_filename = NULL;
	}
}

void queue::set_mode_send( void )
{
	m_mode = QUEUE_MODE_SEND;
}

void queue::set_mode_recv( void )
{
	m_mode = QUEUE_MODE_RECV;
}

void queue::set_filename( const char* filename )
{
	release_filename();

	if( filename )
	{
		size_t size = strlen( filename ) + 1;
		m_filename = (char*)malloc( size );
		snprintf( m_filename, size, "%s", filename );
	}
}

int queue::open( void )
{
	int ret;
	int fd;
	char buf[20];

	if( QUEUE_MODE_RECV == m_mode )
	{
		if( -1 == m_mqd )
		{
			m_mqd = msgget( IPC_PRIVATE, IPC_CREAT );
			if( -1 == m_mqd )
			{
				printf( "msgget() failed\n" );
				return QUEUE_ERR_MSGGET_FAILED;
			}

			fd = ::open( m_filename, O_RDWR | O_CREAT );
			if( -1 == fd )
			{
				printf( "can not read %s\n", m_filename );
				ret = msgctl( m_mqd, IPC_RMID, NULL );
				if( -1 == ret )	printf( "msgctl() failed\n" );
				return QUEUE_ERR_CANNOT_OPEN_FILE;
			}

			memset( buf, 0, 20 );
			snprintf( buf, 20, "%d", m_mqd );

			ret = write( fd, buf, 20 );
			if( -1 == ret || 0 == ret )
			{
				printf( "can not write %s\n", m_filename );
				ret = msgctl( m_mqd, IPC_RMID, NULL );
				if( -1 == ret )	printf( "msgctl() failed\n" );
			}

			::fsync( fd );
			::close( fd );
		}
	}
	else
	{
		fd = ::open( m_filename, O_RDONLY );
		if( -1 == fd )
		{
			printf( "can not read %s\n", m_filename );
			return QUEUE_ERR_CANNOT_OPEN_FILE;
		}

		memset( buf, 0, 20 );
		ret  = read( fd, buf, 20 );
		if( -1 == ret )
		{
			printf( "queue id read error\n" );
			::close( fd );
			return QUEUE_ERR_ID_READ;
		}
		else if( 0 == ret )
		{
			printf( "queue id file blank\n" );
			::close( fd );
			return QUEUE_ERR_ID_BLANK;
		}
		else
		{
			m_mqd = atoi( buf );
		}
		::close( fd );
	}
}

int queue::close( void )
{
	int ret;

	if( QUEUE_MODE_RECV == m_mode )
	{
		if( -1 != m_mqd )
		{
			ret = msgctl( m_mqd, IPC_RMID, NULL );
			if( -1 == ret )
			{
				printf( "msgctl( IPC_RMID ) failed\n" );
				return QUEUE_ERR_MSGCTL_FAILED;
			}
			m_mqd = -1;
		}
	}
	return QUEUE_SUCCESS;
}

void queue::print( void )
{
	printf( "----------------------------------\n" );
	printf( "m_mode : " );
	if( QUEUE_MODE_SEND == m_mode ) printf( "send" );
	if( QUEUE_MODE_RECV == m_mode ) printf( "recv" );
	printf( "\n" );
	printf( "----------------------------------\n" );
	printf( "m_filename : " );
	if( m_filename ) printf( "%s", m_filename );
	printf( "\n" );
	printf( "----------------------------------\n" );
	printf( "m_mqd : %d\n", m_mqd );
	printf( "----------------------------------\n" );
}

int queue::recv( void )
{
	int ret;

	memset( &m_msg, 0, sizeof(msg_t) );

	ret = msgrcv( m_mqd, &m_msg, sizeof(msgcmd_t), 0, IPC_NOWAIT );
	if( -1 == ret )
	{
		//printf( "msgrcv() failed\n" );
		return QUEUE_ERR_MSGRCV_FAILED;
	}

	do_cmd( m_msg.msg.cmd, m_msg.msg.inf );

	//printf( "recv cmd = [%s]\n", m_msg.msg.cmd );
	//printf( "recv inf = [%s]\n", m_msg.msg.inf );

	return QUEUE_SUCCESS;
}

int queue::send( const char* cmd, const char* inf )
{
	int ret;

	memset( &m_msg, 0, sizeof(msg_t) );
	
	m_msg.mtype = 1;
	snprintf( m_msg.msg.cmd, QUEUE_MAX_CMD, "%s", cmd );
	snprintf( m_msg.msg.inf, QUEUE_MAX_INF, "%s", inf );

	ret = msgsnd( m_mqd, &m_msg, sizeof(msgcmd_t), 0 );
	if( -1 == ret )
	{
		printf( "msgsnd() failed\n" );
		return QUEUE_ERR_MSGSND_FAILED;
	}


	return QUEUE_SUCCESS;
}

int queue::list( void )
{
	int max;
	int id;
	struct msqid_ds ds;
	struct msginfo msginfo;

	max = msgctl( 0, MSG_INFO, (struct msqid_ds*)&msginfo );
	if( -1 == max )
	{
		printf( "msgctl( MSG_INFO ) failed\n" );
		return QUEUE_ERR_MSGCTL_FAILED;
	}	

	printf( "------------------------------------------------\n" );
	printf( "max = %d\n", max );

	if( max > 0 )
	{
		printf( "index   id     key    messages\n" );
	
		for( int i = 0; i <= max; i++ )
		{
			id = msgctl( i, MSG_STAT, &ds);
			if( -1 == id )
			{
				printf( "msgctl( MSG_STAT ) failed\n" );
				return QUEUE_ERR_MSGCTL_FAILED;
			}
	
			printf( "%4d %8d 0x08lx %7ld\n",
				i, id, (unsigned long)ds.msg_perm.__key, (long)ds.msg_qnum );
		}
		printf( "------------------------------------------------\n" );
	}
	return QUEUE_SUCCESS;
}

int queue::all_list_clear( void )
{
	int ret;
	int max;
	int id;
	struct msqid_ds ds;
	struct msginfo msginfo;

	max = msgctl( 0, MSG_INFO, (struct msqid_ds*)&msginfo );
	if( -1 == max )
	{
		printf( "msgctl( MSG_INFO ) failed\n" );
		return QUEUE_ERR_MSGCTL_FAILED;
	}	

	if( max > 0 )
	{
		for( int i = 0; i <= max; i++ )
		{
			id = msgctl( i, MSG_STAT, &ds);
			if( -1 == id )
			{
				printf( "msgctl( MSG_STAT ) failed\n" );
				return QUEUE_ERR_MSGCTL_FAILED;
			}
	
			ret = msgctl( id, IPC_RMID, NULL );
			if( -1 == ret )
			{
				printf( "msgctl( IPC_RMID ) failed\n" );
				return QUEUE_ERR_MSGCTL_FAILED;
			}
		}
	}

	return QUEUE_SUCCESS;
}





























