package org.apache.maven.changelog;

/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" and
 *    "Apache Maven" must not be used to endorse or promote products
 *    derived from this software without prior written permission. For
 *    written permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    "Apache Maven", nor may "Apache" appear in their name, without
 *    prior written permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 * ====================================================================
 */

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;

/**
 * Change Log Entry - holds details about revisions to a file.
 *
 * @task add time of change to the entry
 * @task investigate betwixt for toXML method
 * @author <a href="mailto:dion@multitask.com.au">dIon Gillard</a>
 * @version $Id: ChangeLogEntry.java,v 1.2 2003/07/04 16:24:46 evenisse Exp $
 */
public class ChangeLogEntry
{
    /**
     * Escaped <code>&lt;</code> entity
     */
    public static final String LESS_THAN_ENTITY = "&lt;";
    
    /**
     * Escaped <code>&gt;</code> entity
     */
    public static final String GREATER_THAN_ENTITY = "&gt;";
    
    /**
     * Escaped <code>&amp;</code> entity
     */
    public static final String AMPERSAND_ENTITY = "&amp;";
    
    /**
     * Escaped <code>'</code> entity
     */
    public static final String APOSTROPHE_ENTITY = "&apos;";
    
    /**
     * Escaped <code>"</code> entity
     */
    public static final String QUOTE_ENTITY = "&quot;";
    
    /**
     * Formatter used by the getDateFormatted method.
     */
    private static final SimpleDateFormat DATE_FORMAT = 
        new SimpleDateFormat("yyyy-MM-dd");

    /**
     * Formatter used by the getTimeFormatted method.
     */
    private static final SimpleDateFormat TIME_FORMAT = 
        new SimpleDateFormat("HH:mm:ss");

    /**
     * Formatter used to parse CVS date/timestamp.
     */
    private static final SimpleDateFormat CVS_TIMESTAMP_FORMAT =
        new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

    /** Date the changes were committed */
    private Date date;
    
    /** User who made changes */
    private String author;
    
    /** comment provided at commit time */
    private String comment = "";
    
    /** ChangeLogFiles committed on the date, by the author, with comment*/
    private Vector files = new Vector();
    
    /**
     * Constructor for the Entry object
     *
     * @param date the date of the change
     * @param author who made the change
     * @param comment the commit comments for the change
     */
    public ChangeLogEntry(String date, String author, String comment)
    {
        setDate(date);
        setAuthor(author);
        setComment(comment);
    }

    /**
     * Constructor used when attributes aren't available until later
     */
    public ChangeLogEntry() 
    {
    }
    
    /**
     * Adds a file to the list for this entry
     * @param file a {@link ChangeLogFile}
     */
    public void addFile(ChangeLogFile file)
    {
        files.addElement(file);
    }
    
    /** 
     * Adds a feature to the File attribute of the Entry object.
     * @param file the file name committed
     * @param revision the revision of the latest change
     */
    public void addFile(String file, String revision)
    {
        files.addElement(new ChangeLogFile(file, revision));
    }

    /**
     * @return a string representation of the entry
     */
    public String toString()
    {
        return author + "\n" + date + "\n" + files + "\n" + comment;
    }

    /**
     * Provide the changelog entry as an XML snippet.
     * 
     * @task make sure comment doesn't contain CDATA tags - MAVEN114
     * @return a changelog-entry in xml format
     */
    public String toXML()
    {
        StringBuffer buffer = new StringBuffer();

        buffer.append("\t<changelog-entry>\n")
            .append("\t\t<date>")
            .append(getDateFormatted())
            .append("</date>\n")
            .append("\t\t<time>")
            .append(getTimeFormatted())
            .append("</time>\n")
            .append("\t\t<author><![CDATA[")
            .append(author)
            .append("]]></author>\n");
        
        for (Enumeration e = files.elements(); e.hasMoreElements();)
        {
            ChangeLogFile file = (ChangeLogFile) e.nextElement();
            buffer.append("\t\t<file>\n")
                .append("\t\t\t<name>")
                .append(escapeValue(file.getName()))
                .append("</name>\n")
                .append("\t\t\t<revision>")
                .append(file.getRevision())
                .append("</revision>\n");
            buffer.append("\t\t</file>\n");
        }
        buffer.append("\t\t<msg><![CDATA[")
            .append(comment)
            .append("]]></msg>\n");
        buffer.append("\t</changelog-entry>\n");
        
        return buffer.toString();
    }
    
    /**
     * Getter for property author.
     * @return Value of property author.
     */
    public String getAuthor()
    {
        return author;
    }
    
    /**
     * Setter for property author.
     * @param author New value of property author.
     */
    public void setAuthor(String author)
    {
        this.author = author;
    }
    
    /**
     * Getter for property comment.
     * @return Value of property comment.
     */
    public String getComment()
    {
        return comment;
    }
    
    /**
     * Setter for property comment.
     * @param comment New value of property comment.
     */
    public void setComment(String comment)
    {
        this.comment = comment;
    }
    
    /**
     * Getter for property date.
     * @return Value of property date.
     */
    public Date getDate()
    {
        return (Date) date.clone();
    }
    
    /**
     * Setter for property date.
     * @param date New value of property date.
     */
    public void setDate(Date date)
    {
        this.date = new Date(date.getTime());
    }

    /**
     * Setter for property date that takes a string and parses it
     * @param date - a string in yyyy/MM/dd HH:mm:ss format
     */
    public void setDate(String date)
    {
        try
        {
            this.date = CVS_TIMESTAMP_FORMAT.parse(date);
        }
        catch (ParseException e)
        {
            throw new IllegalArgumentException("I don't understand this date: "
                + date);
        }

    }
    
    /**
     * @return date in yyyy-mm-dd format
     */
    public String getDateFormatted()
    {
        return DATE_FORMAT.format(getDate());
    }
    
    /**
     * @return time in HH:mm:ss format
     */
    public String getTimeFormatted()
    {
        return TIME_FORMAT.format(getDate());
    }
    
    /** 
     * <p>Escape the <code>toString</code> of the given object. 
     * For use in an attribute value.</p> 
     * 
     * swiped from jakarta-commons/betwixt -- XMLUtils.java 
     * 
     * @param value escape <code>value.toString()</code> 
     * @return text with characters restricted (for use in attributes) escaped 
     */ 
    public static final String escapeValue(Object value) { 
        StringBuffer buffer = new StringBuffer(value.toString()); 
        for (int i=0, size = buffer.length(); i <size; i++) { 
            switch (buffer.charAt(i)) { 
                case '<': 
                    buffer.replace(i, i+1, LESS_THAN_ENTITY); 
                    size += 3; 
                    i+=3; 
                    break; 
                case '>': 
                    buffer.replace(i, i+1, GREATER_THAN_ENTITY); 
                    size += 3; 
                    i += 3; 
                    break; 
                case '&': 
                    buffer.replace(i, i+1, AMPERSAND_ENTITY); 
                    size += 4; 
                    i += 4; 
                    break; 
                case '\'': 
                    buffer.replace(i, i+1, APOSTROPHE_ENTITY); 
                    size += 4; 
                    i += 4; 
                    break; 
                case '\"': 
                    buffer.replace(i, i+1, QUOTE_ENTITY); 
                    size += 5; 
                    i += 5; 
                    break; 
            } 
        } 
        return buffer.toString(); 
    }
}
