/******************************************************************************
Function: globus_l_gass_server_ez_get_callback()

Description: 

Parameters: 

Returns: 
******************************************************************************/
static void 
globus_l_gass_server_ez_get_callback(
    void *arg,
    globus_gass_transfer_request_t request,
    globus_byte_t *     bytes,
    globus_size_t       len,
    globus_bool_t       last_data)
{
    int fd;
    globus_size_t amt;

    fd=(int) arg;
    if(!last_data)
    {
	amt = globus_libc_read(fd, bytes, len);
        if(amt == 0)
        {
            globus_gass_transfer_send_bytes(request,
                                            bytes,
                                            0,
                                            GLOBUS_TRUE,
                                            globus_l_gass_server_ez_get_callback,
                                            arg);
        }
        else
        {
            globus_gass_transfer_send_bytes(request,
                                            bytes,
                                            amt,
                                            GLOBUS_FALSE,
                                            globus_l_gass_server_ez_get_callback,
                                            arg);
        }
        return;
    }

    if((fd!=fileno(stdout))&&(fd!=fileno(stderr)))
    {
        close(fd);
    }
    globus_free(bytes);
    globus_gass_transfer_request_destroy(request);

} /* globus_l_gass_server_ez_get_callback() */
static void
globus_l_gass_server_ez_register_accept_callback(
					void * listener,
					globus_gass_transfer_request_t request 
					)
{
    int rc;
    char * subjectname;
    char * path=GLOBUS_NULL;
    char * url;
    globus_url_t parsed_url;
    globus_l_gass_server_ez_t * s;
    globus_gass_server_ez_request_t *r;
    struct stat	statstruct;
    globus_byte_t * buf;
    int amt;
    int flags=0;

    
    subjectname=globus_gass_transfer_request_get_subject(request);

    /* lookup our options */
    s=(globus_l_gass_server_ez_t *)globus_hashtable_lookup(
                                &globus_l_gass_server_ez_listeners,
                                listener);

    /* Check for valid URL */
    url=globus_gass_transfer_request_get_url(request);
    rc = globus_url_parse(url, &parsed_url);
    if(rc != GLOBUS_SUCCESS ||
       parsed_url.url_path == GLOBUS_NULL || strlen(parsed_url.url_path) == 0U)
    {
        globus_gass_transfer_deny(request, 404, "File Not Found");
        globus_gass_transfer_request_destroy(request);
        if (rc == GLOBUS_SUCCESS)
            globus_url_destroy(&parsed_url);
	goto reregister_nourl;
    }

    if(globus_gass_transfer_request_get_type(request) ==
       GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND)
    {
        flags = O_CREAT | O_WRONLY | O_APPEND;
    }
    else if(globus_gass_transfer_request_get_type(request) ==
            GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT)
    {
        flags = O_CREAT | O_WRONLY | O_TRUNC;
    }
    switch(globus_gass_transfer_request_get_type(request))
        {
          case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND:
          case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT:

	    /* Check to see if this is a request we are allowed to handle */

            if(((s->options & GLOBUS_GASS_SERVER_EZ_WRITE_ENABLE) == 0UL) &&
              ((s->options & GLOBUS_GASS_SERVER_EZ_STDOUT_ENABLE) == 0UL) &&
              ((s->options & GLOBUS_GASS_SERVER_EZ_STDERR_ENABLE) == 0UL) &&
              ((s->options & GLOBUS_GASS_SERVER_EZ_CLIENT_SHUTDOWN_ENABLE) ==
									 0UL))
    	    {
		goto deny;
            }
	
	    /* Expand ~ and ~user prefix if enaabled in options */
    	    rc = globus_l_gass_server_ez_tilde_expand(s->options,
                                              parsed_url.url_path,
                                              &path);
              
            if(strncmp(path, "/dev/saga", 9) == 0 && 
                    (s->options & GLOBUS_GASS_SERVER_EZ_STDOUT_ENABLE))
            {
                rc = s->fd; // the pipe handle!
            
                goto authorize;
            }
            else if(strncmp(path, "/dev/saga/", 9) == 0)
            {
                goto deny;
            }
                
    	    else if(strcmp(path, "/dev/globus_gass_client_shutdown") == 0)
    	    {
        	if(s->options & GLOBUS_GASS_SERVER_EZ_CLIENT_SHUTDOWN_ENABLE &&
           	   s->callback != GLOBUS_NULL)
        	{
            	    s->callback();
        	}

		goto deny;
    	    }
#ifdef TARGET_ARCH_WIN32
			// The call to open() in Windows defaults to text mode, so
			// we to override it.
			flags |= O_BINARY;
#endif
            rc = globus_libc_open(path, flags, 0600);

            if(rc < 0)
            {
                goto deny;
            }
	
	    authorize:
            globus_gass_transfer_authorize(request, 0);
	    if(s->options & GLOBUS_GASS_SERVER_EZ_LINE_BUFFER)
	    {
	        r=(globus_gass_server_ez_request_t *)globus_malloc(
				sizeof(globus_gass_server_ez_request_t));
		r->fd=rc;
		r->line_buffer=globus_malloc(80);
                r->line_buffer_used= 0UL;
        	r->line_buffer_length = 80UL;
        	r->linebuffer = GLOBUS_TRUE;

		globus_gass_transfer_receive_bytes(request,
						globus_malloc(1024),
						1024,
						1,
						globus_gass_server_ez_put_memory_done,
						r);
	    }
	    else
	    {
                globus_gass_transfer_receive_bytes(request,
                                               globus_malloc(1024),
                                               1024,
                                               1,
                                               globus_l_gass_server_ez_put_callback,
                                               (void *) rc);
	    }
            break;

          case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_GET:
            flags = O_RDONLY;

			/* Expand ~ and ~user prefix if enaabled in options */
            rc = globus_l_gass_server_ez_tilde_expand(s->options,
                                              parsed_url.url_path,
                                              &path);

   	    if((s->options & GLOBUS_GASS_SERVER_EZ_READ_ENABLE) == 0UL)
    	    {
		goto deny;
    	    }
	   
	    if(stat(path, &statstruct)==0)
	    {
#ifdef TARGET_ARCH_WIN32
				// The call to open() in Windows defaults to text mode, 
				// so we to override it.
				flags |= O_BINARY;
#endif
                rc = globus_libc_open(path, flags, 0600);
		fstat(rc, &statstruct);
	    }
	    else
	    {
		globus_gass_transfer_deny(request, 404, "File Not Found");
		globus_gass_transfer_request_destroy(request);
		goto reregister;
	    }

            buf = globus_malloc(1024);
            amt = read(rc, buf, 1024);
            if(amt == -1)
            {
                globus_free(buf);
                goto deny;
            }
            globus_gass_transfer_authorize(request,
                                           statstruct.st_size);

            globus_gass_transfer_send_bytes(request,
                                            buf,
                                            amt,
                                            GLOBUS_FALSE,
                                            globus_l_gass_server_ez_get_callback,
                                            (void *) rc);
	  break;
	default:
	deny:
	  globus_gass_transfer_deny(request, 400, "Bad Request");
	  globus_gass_transfer_request_destroy(request);

	}

  reregister:
    globus_url_destroy(&parsed_url);

  reregister_nourl:
    globus_gass_transfer_register_listen(
				(globus_gass_transfer_listener_t) listener,
				globus_l_gass_server_ez_listen_callback,
				s->reqattr);

    if (path != GLOBUS_NULL) globus_free(path);

} /*globus_l_gass_server_ez_register_accept_callback*/
static
void
globus_l_gram_streamer_local_poll(
    void *                              arg)
{
    globus_gram_streamer_monitor_t *    monitor = arg;
    int                                 rc;
    struct stat                         st;
    unsigned char *                     data;
    off_t                               data_size;
    globus_size_t                       amt;
    globus_bool_t                       last_data;
    int                                 i;
    char *                              save_state_file;
    globus_gram_stream_t *              streams[] =
    {
        &monitor->output_stream,
        &monitor->error_stream,
        NULL
    };
    globus_gram_stream_t *              stream;

    globus_mutex_lock(&monitor->mutex);

    /* Check if remote_io_file has changed */
    rc = stat("remote_io_file", &st);
    if (rc == 0)
    {
        if (st.st_mtime > monitor->remote_io_url_file_time)
        {
            /* Start the termination of the current output streams */
            for (i = 0; streams[i] != NULL; i++)
            {
	    	stream = streams[i];

                switch (stream->state)
                {
                case GLOBUS_GRAM_STREAM_NEW:
                case GLOBUS_GRAM_STREAM_ACTIVE:
                    globus_gass_transfer_fail(
                            stream->handle,
                            globus_l_gram_streamer_fail,
                            monitor);
                    stream->state = GLOBUS_GRAM_STREAM_RESTART;
                    break;
                case GLOBUS_GRAM_STREAM_FAIL:
                case GLOBUS_GRAM_STREAM_DONE:
                    stream->state = GLOBUS_GRAM_STREAM_RESTART_NEW;
                    stream->sent = 0;
                    stream->last_sent = GLOBUS_FALSE;
                    lseek(stream->fd, 0, SEEK_SET);
                    stream->handle = GLOBUS_NULL_HANDLE;
                    break;
                case GLOBUS_GRAM_STREAM_RESTART:
                case GLOBUS_GRAM_STREAM_RESTART_NEW:
                case GLOBUS_GRAM_STREAM_NONE:
                    break;
                }
            }
            monitor->remote_io_url_file_time = st.st_mtime;

            /* Load new state file */
            save_state_file = monitor->request.job_state_file;
            monitor->request.job_state_file = NULL;
            globus_gram_job_manager_request_free(&monitor->request);
            monitor->request.rsl = NULL;
            monitor->request.job_state_file = save_state_file;
            rc = globus_gram_job_manager_state_file_read(&monitor->request);
            if (rc != GLOBUS_SUCCESS)
            {
                fprintf(stderr, "%d:",
                        rc);
                exit(EXIT_FAILURE);
            }

            if (monitor->output_stream.source != NULL)
            {
                free(monitor->output_stream.source);
                monitor->output_stream.source = NULL;
            }
            if (monitor->output_stream.destination != NULL)
            {
                free(monitor->output_stream.destination);
                monitor->output_stream.destination = NULL;
            }
            if (monitor->error_stream.source != NULL)
            {
                free(monitor->error_stream.source);
                monitor->error_stream.source = NULL;
            }
            if (monitor->error_stream.destination != NULL)
            {
                free(monitor->error_stream.destination);
                monitor->error_stream.destination = NULL;
            }
            /* Re-evaluate RSL */
            rc = globus_l_gram_streamer_get_destinations(
                    monitor);
        }
    }

    /* On the first poll after everything is ready to restart, we'll reload
     * state information and reopen the stream
     */
    for (i = 0; streams[i] != NULL; i++)
    {
        stream = streams[i];

	if (stream->state == GLOBUS_GRAM_STREAM_RESTART_NEW)
	{
	    /* Re-open output stream */
	    if (stream->fd != -1 &&
		stream->destination != NULL)
	    {
		rc = globus_l_gram_streamer_open_destination(
			monitor,
			stream);
		if (rc == GLOBUS_SUCCESS)
		{
		    stream->state = GLOBUS_GRAM_STREAM_NEW;
		}
		else
		{
		    stream->state = GLOBUS_GRAM_STREAM_FAIL;
		}
	    }
	    else
	    {
		stream->state = GLOBUS_GRAM_STREAM_DONE;
	    }
	}
    }

    /* Only queue data if the transfer is alive */
    for (i = 0; streams[i] != NULL; i++)
    {
        stream = streams[i];

        if (stream->state == GLOBUS_GRAM_STREAM_ACTIVE &&
            (fstat(stream->fd, &st) == 0))
        {
            data_size = st.st_size - stream->sent;
            if (data_size > STREAMER_BLOCKSIZE)
            {
                data_size = STREAMER_BLOCKSIZE;
            }
            amt = 0;

            data = NULL;
            if (data_size > 0)
            {
                data = malloc((size_t) data_size);

                do
                {
                    rc = read(stream->fd, data + amt, data_size - amt);
                    if (rc < 0)
                    {
                        if (errno != EINTR)
                        {
                            break;
                        }
                    }
                    else if (rc == 0)
                    {
                        break;
                    }
                    else
                    {
                        amt += rc;
                    }
                }
                while (amt < data_size);
            }
            if (amt > 0 || ((monitor->pid_count == 0) && (!stream->last_sent)))
            {
                stream->sent += amt;
                stream->blocks++;

                last_data = (monitor->pid_count == 0) &&
                            (stream->sent == st.st_size);

                rc = globus_gass_transfer_send_bytes(
                        stream->handle,
                        (data == NULL) ? malloc(1) : data,
                        amt,
                        last_data,
                        globus_l_gram_streamer_data_callback,
                        monitor);
                switch (rc)
                {
                case GLOBUS_SUCCESS:
                    stream->last_sent = last_data;
                    break;
                case GLOBUS_GASS_TRANSFER_ERROR_NULL_POINTER:
                    fprintf(stderr, "NULL pointer");
                    exit(EXIT_FAILURE);
                    break;
                case GLOBUS_GASS_TRANSFER_ERROR_INVALID_USE:
                    stream->last_sent = GLOBUS_TRUE;
                    globus_gass_transfer_request_destroy(stream->handle);
                    stream->state = GLOBUS_GRAM_STREAM_FAIL;
                    break;
                case GLOBUS_GASS_TRANSFER_ERROR_NOT_INITIALIZED:
                    fprintf(stderr, "Not initialized");
                    exit(EXIT_FAILURE);
                    break;
                case GLOBUS_GASS_TRANSFER_REQUEST_FAILED:
                    fprintf(stderr, "Failed ");
                    exit(EXIT_FAILURE);

                }
            }
        }
    }
    globus_mutex_unlock(&monitor->mutex);
}