import com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl;
import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Hashtable;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * Quick and dirty code to updates an RSS xml podcasting file.
 * Based on the example here: http://www.apple.com/itunes/store/podcaststechspecs.html#_Toc526931673
 * 
 * @author Maurice Walton, www.mauricewalton.com 2007
 */
public class MythPodcastMaker
{
    /**
     * Method comment.
     * 
     * @param args
     */
    public static void main(String[] args)
    {
        boolean error = false;

        if (args.length != 22)
        {
            StringBuilder sb = new StringBuilder();
            sb.append("Usage:\n");
            sb.append("-title     \"podcast item title\"\n");
            sb.append("-subtitle  \"podcast item subtitle\"\n");
            sb.append("-summary   \"podcast summary\"\n");
            sb.append("-holding   \"holding url, i.e.\" \"http://myhomepage/podcasts\"\n");
            sb.append("-keywords  \"a list of keywords seperated by spaces\"\n");
            sb.append("-starttime \"yyyyMMddHHmmss\"\n");
            sb.append("-endtime   \"yyyyMMddHHmmss\"\n");
            sb.append("-author    \"author, i.e. channel\"\n");
            sb.append("-xml       \"File name of the xml document to update\", i.e. \"mythtv.xml\"\n");
            sb.append("-keep      \"Number of items to keep in the podcast\", i.e. \"-1\" for keep all\n");
            sb.append("-file      \"Full path of file to be added\", i.e. \"/var/share/Just a Minute.m4a\"\n");
            sb.append("\nNote that parameter values must be enclosed with \" marks if they contain spaces, parameter order does not matter\n");
            System.out.println(sb.toString());
            error = true;
        }

        Hashtable<String, String> parameters = new Hashtable<String, String>();

        if (!error)
        {
            for (int argsIndex = 0; argsIndex < args.length; argsIndex += 2)
                parameters.put(args[argsIndex], args[argsIndex + 1]);

            if (!parameters.containsKey("-title"))
            {
                System.out.println("missing -title");
                error = true;
            }
            if (!parameters.containsKey("-subtitle"))
            {
                System.out.println("missing -subtitle");
                error = true;
            }
            if (!parameters.containsKey("-summary"))
            {
                System.out.println("missing -summary");
                error = true;
            }
            if (!parameters.containsKey("-holding"))
            {
                System.out.println("missing -holding");
                error = true;
            }
            if (!parameters.containsKey("-keywords"))
            {
                System.out.println("missing -keywords");
                error = true;
            }
            if (!parameters.containsKey("-starttime"))
            {
                System.out.println("missing -starttime");
                error = true;
            }
            if (!parameters.containsKey("-endtime"))
            {
                System.out.println("missing -endtime");
                error = true;
            }
            if (!parameters.containsKey("-keep"))
            {
                System.out.println("missing -keep");
                error = true;
            }
            if (!parameters.containsKey("-xml"))
            {
                System.out.println("missing -xml");
                error = true;
            }
            if (!parameters.containsKey("-keep"))
            {
                System.out.println("missing -keep");
                error = true;
            }
            if (!parameters.containsKey("-file"))
            {
                System.out.println("missing -file");
                error = true;
            }
        }

        if (!error)
        {
            System.out.println("Values:");
            for (String key : parameters.keySet())
            {
                System.out.println(key + "=" + parameters.get(key));
            }
            MythPodcastMaker mpc = new MythPodcastMaker();
            mpc.updatePodcast(parameters);
        }

        if (error)
            System.exit(1);
    }

    private SimpleDateFormat pubDateFormat = new SimpleDateFormat(
                    "EEE, dd MMM yyyy HH:mm:ss z");

    private SimpleDateFormat sourceDateFormat = new SimpleDateFormat(
                    "yyyyMMddHHmmss");


    /**
     * Constructor comment.
     * 
     * @param parameters
     */
    public MythPodcastMaker()
    {
        super();
    }


    /**
     * Update RSS XML.
     * @param parameters
     * @return
     */
    public boolean updatePodcast(Hashtable<String, String> parameters)
    {
        File file = new File(parameters.get("-file"));
        boolean success = true;
        try
        {
            DocumentBuilder db;
            db = DocumentBuilderFactoryImpl.newInstance().newDocumentBuilder();
            try
            {
                Document document = db.parse(new File(parameters.get("-xml")));
                NodeList channelNodeList = document.getElementsByTagName("channel");
                Node channelNode = channelNodeList.item(0);

                // first remove any old items, keeping the number required
                // TODO complete this unused functionality by also optionally deleting the associated files
                int itemsToKeep = Integer.parseInt(parameters.get("-keep"));
                if (itemsToKeep > -1)
                {
                    // remove items until "keep" number of items are left
                    NodeList itemList = document.getElementsByTagName("item");
                    if (itemList.getLength() > itemsToKeep)
                    {
                        while (itemList.getLength() > itemsToKeep)
                        {
                            Node removeNode = itemList.item(0);
                            channelNode.removeChild(removeNode);
                        }
                    }
                }

                // add new item to channel node
                Node itemNode = document.createElement("item");

                Node titleNode = document.createElement("title");
                titleNode.appendChild(document.createTextNode(parameters.get("-title")));
                itemNode.appendChild(titleNode);

                Node authorNode = document.createElement("itunes:author");
                authorNode.appendChild(document.createTextNode(parameters.get("-author")));
                itemNode.appendChild(authorNode);

                Node subtitleNode = document.createElement("itunes:subtitle");
                subtitleNode.appendChild(document.createTextNode(parameters.get("-subtitle")));
                itemNode.appendChild(subtitleNode);

                Node summaryNode = document.createElement("itunes:summary");
                summaryNode.appendChild(document.createTextNode(parameters.get("-summary")));
                itemNode.appendChild(summaryNode);

                Element enclosureNode = document.createElement("enclosure");
                enclosureNode.setAttribute("url", parameters.get("-holding")
                                + "/" + file.getName());
                enclosureNode.setAttribute("length",
                                Long.toString(file.length()));
                enclosureNode.setAttribute("type", "audio/x-m4a");
                itemNode.appendChild(enclosureNode);

                Node guidNode = document.createElement("guid");
                guidNode.appendChild(document.createTextNode(parameters.get("-holding")
                                + "/" + file.getName()));
                itemNode.appendChild(guidNode);

                Date startdate = new GregorianCalendar().getTime();
                try
                {
                    startdate = sourceDateFormat.parse(parameters.get("-starttime"));
                }
                catch (ParseException e)
                {
                    e.printStackTrace();
                    success = false;
                }
                Node pubDateNode = document.createElement("pubDate");
                pubDateNode.appendChild(document.createTextNode(pubDateFormat.format(startdate)));
                itemNode.appendChild(pubDateNode);

                Date enddate = new GregorianCalendar().getTime();
                try
                {
                    enddate = sourceDateFormat.parse(parameters.get("-endtime"));
                }
                catch (ParseException e)
                {
                    e.printStackTrace();
                    success = false;
                }
                Node durationNode = document.createElement("itunes:duration");
                long milliseconds = enddate.getTime() - startdate.getTime();
                long seconds = milliseconds / 1000L;
                long minutes = seconds / 60L;
                seconds = seconds - (minutes * 60L);
                String secondsString = Long.toString(seconds);
                if (seconds < 10)
                    secondsString = "0" + secondsString;
                durationNode.appendChild(document.createTextNode(Long.toString(minutes)
                                + ":" + secondsString));
                itemNode.appendChild(durationNode);

                Node keywordsNode = document.createElement("itunes:keywords");
                keywordsNode.appendChild(document.createTextNode(parameters.get(
                                "-keywords").replaceAll(" ", ", ")));
                itemNode.appendChild(keywordsNode);

                if (success)
                {
                    channelNode.appendChild(itemNode);
                    success = writeXmlFile(document, new File(
                                    parameters.get("-xml")));
                }
            }
            catch (SAXException e)
            {
                e.printStackTrace();
                success = false;
            }
            catch (IOException e)
            {
                e.printStackTrace();
                success = false;
            }
        }
        catch (ParserConfigurationException e)
        {
            e.printStackTrace();
            success = false;
        }

        return success;
    }


    /**
     * Write the xml document in a formatted manner for easier reading by humans.
     * 
     * @param document
     * @param file
     * @return success
     */
    public boolean writeXmlFile(Document document, File file)
    {
        boolean success = true;

        OutputFormat format = new OutputFormat(document);
        format.setIndenting(true);
        format.setIndent(2);
        format.setLineWidth(500);
        try
        {
            XMLSerializer output = new XMLSerializer(
                            new FileOutputStream(file), format);
            output.serialize(document);
        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
            success = false;
        }
        catch (IOException e)
        {
            e.printStackTrace();
            success = false;
        }
        return success;
    }

}

// template
/*
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0">
    <channel>
        <title>Maurice's MythTV DVB Radio Recordings</title>
        <link>http://www.YOURSERVER.co.uk/mythtv/index.html</link>
        <language>en-us</language>
        <copyright>&#x2117; &amp; &#xA9; 2007 Maurice Walton, content, probably the BBC.</copyright>
        <itunes:subtitle>MythTV DVB Radio Recordings</itunes:subtitle>
        <itunes:author>Maurice Walton</itunes:author>
        <itunes:summary>MythTV DVB Radio Recordings</itunes:summary>
        <description>Recorded from Freeview DVB using MythTV, converted to m4a using mplayer and faac</description>
        <itunes:owner>
        <itunes:name>Maurice Walton</itunes:name>
        <itunes:email>someone@somewhere.com</itunes:email>
        </itunes:owner>
        <!--
        <itunes:image href="http://example.com/podcasts/everything/AllAboutEverything.jpg" />
        -->
        <itunes:category text="TV &amp; Film"/>
    </channel>
</rss>
 */

