package page.tools.xml;

import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.wikiwebserver.core.WareHouse;

import page.tools.xml.WikiParser;


public class RSSParser extends WikiParser {
    
    private List<RSSChannel> channels;
    
    private RSSChannel currentChannel;
    private RSSItem currentItem;
    
    private boolean isChannelDescriptor = true;
    
    private Map<String, String> textReplacements;
    private DateFormat dateFormat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z");
    
    public RSSParser() {
        channels = new ArrayList<RSSChannel>();
        textReplacements = new HashMap<String, String>();
        textReplacements.put("\r", " ");
        textReplacements.put("\n", " ");
        textReplacements.put("&gt;", ">");
        textReplacements.put("&lt;", "<");
        textReplacements.put("&amp;", "&");        
    }
    
    public RSSChannel getChannel(InputStream in) throws ParseException, IOException {
        List<RSSChannel> channels = getChannels(in);
        if (channels == null || channels.size() == 0) return null;
        return channels.get(0);
    }
    
    public List<RSSChannel> getChannels(InputStream in) throws ParseException, IOException {
        String rss = this.getXMLAsString(in);
        if (rss == null) return new ArrayList<RSSChannel>();
        parse(rss);
        return channels;
    }
    

    public void openTag(String tagName, Map<String, String> attributes) {   
        //System.out.println(tagName + " " + getTextAfterTag());
        if (tagName.equals("channel")) {
            isChannelDescriptor = true;
            currentChannel = new RSSChannel();
        } 
        
        else if (tagName.equals("item")) {
            isChannelDescriptor = false;
            currentItem = new RSSItem();
        } 
        
        else if (tagName.equals("title")) {
            if (isChannelDescriptor) {
                currentChannel.setTitle(getTextAfterTag());
            } else {            
                currentItem.setTitle(getTextAfterTag());
            }
        }
        
        else if (tagName.equals("description")) {
            if (isChannelDescriptor) {
                currentChannel.setDescription(getTextAfterTag());
            } else {
                currentItem.setDescription(getTextAfterTag());
            }
        }
        
        else if (tagName.equals("link")) {
            if (isChannelDescriptor) {
                currentChannel.setLink(getTextAfterTag());
            } else {
                currentItem.setLink(getTextAfterTag());
            }
        }        
        
        else if (tagName.equals("pubdate")) {
            long time;
            try {
                time = dateFormat.parse(getTextAfterTag()).getTime();
            } catch (ParseException e) {
                time = System.currentTimeMillis();
            }
            if (isChannelDescriptor) {
                currentChannel.setPubDate(time);
            } else {
                currentItem.setPubDate(time);
            }
        }
        
        else if (tagName.equals("guid")) {
            currentItem.setGuid(getTextAfterTag());
        }          
          
    }
    
    public void closeTag(String tagName) {
       
        if (tagName.equals("item")) {          
            if (currentItem.getPubDate() == -1) {
                currentItem.setPubDate(System.currentTimeMillis());
            }            
            currentChannel.addItem(currentItem);
        }
        
        else if (tagName.equals("channel")) {
            channels.add(currentChannel);
        }        
    }
    
    public String getTextAfterTag() {
        String text = super.getTextAfterTag();
        if (text == null) return null;
        
        // Replace entities
        text = WareHouse.performFindReplace(text, textReplacements);
        // Strip HTML
        text = text.replaceAll("\\<.*?>","");
        // Remove redundant spaces
        return text.replaceAll("  ", " ");
    }
    
    
    private String getXMLAsString(InputStream in) throws IOException {

        // Download the RSS
        byte[] raw = WareHouse.streamToByteArray(in);
        
        // Read the beginning to figure out the text encoding
        int identSize = raw.length > 256 ? 256 : raw.length;
        String ident = new String(raw, 0, identSize, "utf8");
        String encoding = WareHouse.getBetween("encoding=\"", "\"", ident);
        if (encoding == null) encoding = "utf8";
        
        // Return a string of the bytes using specified encoding
        return new String(raw, encoding);     

    }    
}

