/*
 * @(#)NTParser.java
 *
 * Copyright (c) 2003 JSCAPE
 * 1147 S. 53rd Pl., Mesa, Arizona, 85206, U.S.A.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * JSCAPE. ("Confidential Information").  You shall not disclose such
 * Confidential Information and shall use it only in accordance with
 * the terms of the license agreement you entered into with JSCAPE.
 */
package com.jscape.inet.ftp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Parser responsible for handling FTP directory listing returned in the Windows NT format.
 * The following is a partial example listing of the format expected.
 * <p/>
 * <pre>
 * 06-03-99  10:57PM                    1 NotCurrentYear.txt
 * 03-06-00  09:11PM                    1 CurrentYear.txt
 * 03-06-00  09:18PM  &lt;DIR&gt; tmp
 * </pre>
 */
@SuppressWarnings("unchecked")
public class NTParser
        implements FtpFileParser {

    private UnixParser unixParser = null;


    /**
     * Parses directory listing.
     * Reads directory listing from FTP server and parses contents into an Enumeration of FtpFile.
     *
     * @param in the BufferedReader passed in by Ftp class when invoking Ftp#getDirListing method.
     *
     * @return an Enumeration of FtpFile
     *
     * @see FtpFile
     * @see Ftp#getDirListing
     */
    public Enumeration parse(BufferedReader in)
            throws IOException {
        Vector files = new Vector();

        String line = in.readLine();

        // check if should be UnixParser instead of NTParser
        if (line != null) {
            char firstChar = line.charAt(0);
            if (Character.isDigit(firstChar)) {
                FtpFile file = parseLine(line);
                if (file != null) {
                    files.addElement(file);
                }
            } else {
                StringBuffer buffer = new StringBuffer();
                buffer.append(line);
                buffer.append("\r\n");
                while ((line = in.readLine()) != null) {
                    buffer.append(line);
                    buffer.append("\r\n");
                }
                StringReader sr = new StringReader(buffer.toString());
                unixParser = new UnixParser();
                return unixParser.parse(new BufferedReader(sr));
            }
        }

        while ((line = in.readLine()) != null) {
            FtpFile file = parseLine(line);

            if (!(file == null)) {
                files.addElement(file);
            }
        }
        return files.elements();
    }

    /**
     * Gets the date and time for an FtpFile entry sourced from an NT directory listing.
     *
     * @param file   the FtpFile
     * @param zone   the TimeZone to use when calculating time. Your default timezone is used if not provided.
     * @param locale the Locale to use when parsing date. Locale.US is used if not provided.
     *
     * @return a Date, or null if FtpFile#getDate or FtpFile#getTime values are null
     *
     * @throws ParseException if an error occurs while parsing entry
     * @see java.util.TimeZone
     * @see java.util.Locale
     * @see FtpFile
     */
    public Date getDateTime(FtpFile file, TimeZone zone, Locale locale)
            throws ParseException {

        if (unixParser != null) {
            return unixParser.getDateTime(file, zone, locale);
        }

        SimpleDateFormat df = null;

        if (locale != null) {
            df = new SimpleDateFormat("MM-dd-yy hh:mma", locale);
        } else {
            df = new SimpleDateFormat("MM-dd-yy hh:mma", Locale.US);
        }

        if (zone != null) {
            df.setTimeZone(zone);
        }
        return df.parse(file.getDate() + " " + file.getTime());
    }

    /**
     * Gets the date and time for an FtpFile entry sourced from an NT directory listing.
     *
     * @param file the FtpFile
     *
     * @throws ParseException if an error occurs while parsing entry
     * @see FtpFile
     */
    public Date getDateTime(FtpFile file)
            throws ParseException {
        return getDateTime(file, null, null);
    }

    /**
     * Parses contents of each line in directory listing returning a single FtpFile.
     *
     * @param line the line of data to parse
     *
     * @return a FtpFile
     *
     * @see FtpFile
     */
    private FtpFile parseLine(String line) {
        // MS-DOS Style
        //06-03-99  10:57PM                    1 NotCurrentYear.txt
        //03-06-00  09:11PM                    1 CurrentYear.txt
        //03-06-00  09:18PM   <DIR>            tmp
        StringTokenizer st = new StringTokenizer(line);
        FtpFile file = new FtpFile("", line, this);

        file.setDate(st.nextToken());
        file.setTime(st.nextToken());

        String tmp = st.nextToken();

        if (tmp.equalsIgnoreCase("<DIR>")) {
            file.setDirectory(true);
        } else {
            file.setFilesize(tmp);
        }

        String fileName = getFileName(line);
        file.setFilename(fileName);

        return file;
    }

    /**
     * Get the file or directory name from line.
     *
     * @param line Line to parse.
     *
     * @return The file name
     */
    private String getFileName(String line) {
        String name = null;
        int startFileName = getFileNameIndex(line);
        name = line.substring(startFileName);
        return name;
    }

    /**
     * Gets starting file name index.
     *
     * @param line The file name.
     *
     * @return Starting file name index.
     */
    private int getFileNameIndex(String line) {
        int idx = 0;

        StringTokenizer st = new StringTokenizer(line, " ", true);
        int tokenCount = 0;

        while (st.hasMoreElements()) {
            String t = st.nextToken();
            if (!t.equals(" ")) {
                tokenCount++;
                if (tokenCount == 4) {
                    break;
                } else {
                    idx = t.length() + idx;
                }
            } else {
                idx++;
            }
        }

        return idx;
    }

    /**
     * Parses a string which contains a date and returns a date object
     *
     * @param date The string will be parsed
     *
     * @return A object date which corresponds with the input string argument
     *
     * @throws ParseException if an error ocurrs
     */
    public Date getFileDate(String date)
            throws ParseException {
        if (unixParser != null) {
            return unixParser.getFileDate(date);
        }

        // Format spected 06-03-99
        Date fileDate = null;
        try {
            SimpleDateFormat format = new SimpleDateFormat("dd-MM-yy");
            fileDate = format.parse(date);
        } catch (ParseException e) {
            SimpleDateFormat format = new SimpleDateFormat("MM-dd-yy");
            fileDate = format.parse(date);
        }
        return fileDate;
    }


}
