import gov.noaa.ncdc.publications.exception.ConvertException;
import gov.noaa.ncdc.publications.exception.CreatePDFFileException;
import gov.noaa.ncdc.publications.exception.CreateTempWorkingDirException;
import gov.noaa.ncdc.publications.exception.FTPServerException;
import gov.noaa.ncdc.publications.exception.FTPServerTimeoutException;
import gov.noaa.ncdc.publications.exception.createListFileException;
import gov.noaa.ncdc.util.FileUtils;
import gov.noaa.ncdc.util.Registry;
import gov.noaa.ncdc.util.WssrdFileComparator;
import gov.noaa.ncdc.util.ftpServer.FtpServer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

import java.util.Arrays;


/**
 * <p>
 * <CODE>RemotePublication</CODE> RemotePublication is a publication
 * stored as TIF files in the WSSRD database.
 * </p>
 * <pre>
 * Revision 1.1  2003/10/15 13:11:18  othomann
 * Fix for 44839
 *
 * Revision 1.6  2003/10/09 22:07:28  jduska
 * Merged Chaged from 1.3 Branch into  Head
 *
 * Revision 1.5.2.2  2003/10/01 22:48:03  jduska
 * Added support, so that the publication can be retrieved by WSSRD cabinet 
 * and WSSRD docID
 *
 * Revision 1.5.2.1  2003/09/17 18:20:48  jduska
 * Change FTP Errors to Warnings
 *
 * Revision 1.5  2003/07/25 20:49:52  jduska
 * - Updated the Publication Library to use a new renameFile method 
 * - Created the new FileUtils class by moving the copyFile and adding the renameFile
 * methods
 *
 * Revision 1.4  2003/07/17 23:56:58  jduska
 * - Updated to support new support files in the command line tool	
 * - Update the properties to support the dynamic changing the FTP library
 * - Cleaned up the exceptions and few other files with outdate or unneed imports and etc
 * 
 * Revision 1.3  2003/07/07 15:42:48  jduska
 * - Corrected bugs in new changes to support the Publication Library
 * 
 * Revision 1.2  2003/07/02 17:33:14  jduska
 * - bug fix to correct the Temporary Directory
 *   issue when using the library within a web application
 * 
 * Revision 1.1  2003/06/26 23:54:10  jduska
 * - Command Line version of the Publication Library
 * 
 * Revision 1.3  2003/06/26 23:43:21  jduska
 * - Changes to support using the PDF Library on the command line
 * 
 * Revision 1.1  2003/06/09 21:27:29  jduska
 * - Updated the library, so works on Windows
 * 
 * Revision 1.1  2003/01/24 18:43:58  jduska
 * More refactoring of the SerialPublications to
 * support the local documents
 * 
 * Revision 1.3  2002/10/11 21:03:50  jduska
 *  keyword substitution change ***
 * 
 * </pre>
 */
public class RemotePublication extends Publication {
	private static final String PDF_FILETYPE = "PDF";
	private static Log log =
		LogFactory.getLog(RemotePublication.class.getName());
	private String _fileList;
	private String _fileType;
	protected String _pages[];

	protected RemotePublication(String id, String year, String month,
								String stateCode,
								String serverDirectory, String cabinet) {
		super(id, year, month, stateCode, serverDirectory, cabinet);
		_fileList = _cabinet + '~' + id + ".txt";
	}

	public boolean getDocument() {
		int attempt = 0;

		while (attempt < _maxAttempts) {
			try {
				attempt++;
				log.info("*** Downloading " + _localFilename +
						 EXTENTION + " attempt " + attempt +
						 " out of " + _maxAttempts);

				if (getRemoteDocument()) {
					log.info("Success document published " +
							 _localFilename + EXTENTION);

					return true;
				}
			} catch (ConvertException e) {
                
				log.warn(e);
			}
		}

		return false;
	}

	protected boolean getRemoteDocument() throws ConvertException {
		boolean successful = false;

		try {
			createTempWorkingDir();
			getPages();

			if (_fileType != PDF_FILETYPE) {
				createListFile();
				createPDFFile();
			} else {
				renamePDFFile();
			}

			successful = true;
		} catch (FTPServerTimeoutException e) {
			String msg =
				"Convert process timed out retriving TIFF page" +
				e.getFileName();
			log.warn(msg);
			throw new ConvertException(msg);
		} catch (FTPServerException e) {
			String msg =
				"Convert process encounter an " + e.getMessage();
			log.warn(msg);
			throw new ConvertException(msg);
		} catch (CreateTempWorkingDirException e) {
			String msg =
				"Error: Covert could not create a Working Directory!";
			log.warn(msg);
			throw new ConvertException(msg);
		} catch (CreatePDFFileException e) {
			String msg =
				"Could not create the PDF file  " + e.getMessage();
			log.warn(msg);
			throw new ConvertException(msg);
		} catch (createListFileException e) {
			String msg =
				"Could not create the c42pdf List File" +
				e.getMessage();
			throw new ConvertException(msg);
		} catch (NoFTPServiceException e) {
			String msg =
				"Could not create the FTP Service " + e.getMessage();
			log.warn(msg);
			throw new ConvertException(msg);
		}

		return successful;
	}

	protected void getPages()
					 throws FTPServerTimeoutException, 
							FTPServerException, NoFTPServiceException {
		// Setup the ftp server
		FtpServer ftp;

		try {
			ftp = (FtpServer) Class.forName(Registry.getFTPService())
								   .newInstance();
			ftp.setServer(Registry.getUrl());
			ftp.setPassword(Registry.getFtpPassword());
			ftp.setUserName(Registry.getFtpUserName());
			ftp.setPassive(Registry.usePassive());
			ftp.setTimeout(Registry.getFtpTimeout());

			// get the pages and store them in the _workingDir
			_pages =
				ftp.getFiles(getWssrdDocumentName(), _workingDir);

			if ((_pages.length == 1) && _pages[0].endsWith(".PDF")) {
				_fileType = PDF_FILETYPE;
			}
		} catch (InstantiationException e) {
			log.warn(e.getMessage());
			throw new NoFTPServiceException();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	protected void createPDFFile() throws CreatePDFFileException {
		String cmdLine = null;

		try {
			File newPdfFile =
				new File(_workingDir + File.separator +
						 _localFilename + EXTENTION);

			if (Registry.isCommandLineMode()) {
				handleMultipleDocuments(newPdfFile);
			}

			cmdLine = createC42PDFCommandLine(newPdfFile.getName());

			if (log.isDebugEnabled()) {
				log.debug("Running " + cmdLine);
			}

			// run C42PDF to create the file & wait till it finishes.
			Process p = Runtime.getRuntime().exec(cmdLine);
			p.waitFor();

			// check to see if it worked
			if (!newPdfFile.exists()) {
				log.warn("PDF File was not created!");
				throw new CreatePDFFileException("PDF File was not created!");
			}
		} catch (IOException e) {
			e.printStackTrace();
			throw new CreatePDFFileException(e.toString());
		} catch (InterruptedException e) {
			e.printStackTrace();
			throw new CreatePDFFileException(e.toString());
		}

		return;
	}

	/**
	 * generates the command line need to execute the C42PDF tool in
	 * a shell. This requires that the
	 * <code>Registry.getConvertToolPath()</code> and
	 * <code>Registry.getConvertToolName()</code> are  valid.
	 *
	 * @param documentName the name of the document you wish to
	 *        create
	 *
	 * @return
	 */
	private String createC42PDFCommandLine(String documentName) {
		return (Registry.getConvertToolPath() + File.separator +
			   Registry.getConvertToolName() +
			   (" -o " + _workingDir + File.separator + documentName +
			   " -l " + _workingDir + File.separator + _fileList));
	}

	/**
	 * there a special cases within WSSRD where there may be more
	 * than one PDF that makes up the document. For example River
	 * Basin documents. Thus, it is possible for the same document
	 * already exist when using this libarary via  a command line
	 * mode. <code>handleMultipleDocuments</code> will add a index
	 * counter to end of each duplicate filename. Thus, if there are
	 * three files for this document the files would be name
	 * filename1, filename2 and filename3
	 *
	 * @param newPdfFile name of the document we are making sure does
	 *        already exist
	 */
	private void handleMultipleDocuments(File newPdfFile) {
		int documentCount = 0;
		String newFilename;

		if (log.isDebugEnabled()) {
			log.debug("Checking to see if " + newPdfFile.getName() +
					  "already exists");
		}

		while (newPdfFile.exists()) {
			documentCount++;
			newFilename =
				(new StringBuffer(_workingDir).append(File.separator)
											  .append(_localFilename)
											  .append(documentCount)
											  .append(EXTENTION)).toString();

			if (log.isDebugEnabled()) {
				log.debug("File already exists. Check to see if we need rename existing file");
			}

			if (documentCount == 1) {
				File backupPdfFile = new File(newFilename);
				newPdfFile.renameTo(backupPdfFile);
			}

			newPdfFile = new File(newFilename);
		}

		return;
	}

	protected void createListFile() throws createListFileException {
		PrintWriter tiffFileListFile = null;

		String s;

		// Must have pages to sort! 
		if (_pages.length == 0) {
			log.error("Internal Error: _tiffPage == null!");
			throw new createListFileException("No pages found in the document!");
		}

		// Sort TIFF files into the correct page order
		WssrdFileComparator fileComparator =
			new WssrdFileComparator();
		Arrays.sort(_pages, fileComparator);

		if (log.isDebugEnabled()) {
			log.debug("Creating list file for C42PDF");
		}

		try {
			File tiffFileList =
				new File(_workingDir + File.separator + _fileList);

			if (tiffFileList.exists()) {
				tiffFileList.delete();
			}

			tiffFileListFile =
				new PrintWriter(new BufferedWriter(new FileWriter(_workingDir +
																  File.separator +
																  _fileList)));

			for (int i = 0; i < _pages.length; i++) {
				s = _workingDir + File.separator + _pages[i];

				if (log.isDebugEnabled()) {
					log.debug(s);
				}

				tiffFileListFile.println(s);
			}
		} catch (IOException e) {
			e.printStackTrace();
			throw new createListFileException(e.toString());
		} finally {
			if (tiffFileListFile != null) {
				tiffFileListFile.close();
			}

			if (log.isDebugEnabled()) {
				log.debug("Finished Creating list file for C42PDF");
			}

			return;
		}
	}

	protected void renamePDFFile() throws CreatePDFFileException {
		String newFileName =
			_workingDir + File.separator + _localFilename +
			EXTENTION;
		String oldWssrdFile =
			_workingDir + File.separator + _pages[0];

		try {
			FileUtils.renameFile(oldWssrdFile, newFileName);
		} catch (IOException e) {
			
			String msg = "The following error occurred "  + e.getMessage();
			log.warn(msg);
			throw new CreatePDFFileException("Could not rename PDF File");
		}

       
	}
}