package phex.metalink;

import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.SAXException;

import phex.utils.NLogger;
import com.bitzi.util.Base32;

// FIXME: Catch "file without name" and doublecheck code.

public class MetalinkUtils
{
    private List<String> magnets;
    private InputStream inStream;
    
    public MetalinkUtils( InputStream inStream )
    {
        magnets = new ArrayList<String>();
        this.inStream = inStream;
    }
        
    
    public void start( ) 
        throws IOException
    {
        // Use an instance of DMetalink as the SAX event handler
        DMetalink metalink = new DMetalink();
        MetalinkSAXHandler handler = new MetalinkSAXHandler(metalink);
        // Use the default (non-validating) parser
        SAXParserFactory factory = SAXParserFactory.newInstance();
        // Parse the input
        SAXParser saxParser;
        
        try
        {
            saxParser = factory.newSAXParser();
            
            saxParser.parse( inStream, handler);
            
            int i = 0;
            for(DMetalink.FileEntry f : metalink.files)
            {
                magnets.add(magnet(f));
            }
        }
        catch ( ParserConfigurationException exp )
        {
            NLogger.error( MetalinkUtils.class, exp, exp );
            throw new IOException( "Parsing Metalink XML failed." );
        }
        catch ( SAXException exp )
        {
            NLogger.error( MetalinkUtils.class, exp, exp );
            throw new IOException( "Parsing Metalink XML failed." );
        }
    }
    
    public List getMagnets ()
    {
        return magnets;
    }
    
    //magnet:?xt=urn:sha1:YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5C&dn=Great+Speeches+-+Martin+Luther+King+Jr.+-+I+Have+A+Dream.mp3
    //bitte erläutern: &xs= , &as= , ... -> ok hab ich von de.wikipedia.org (auf en.... stands nicht)
    //Warum steht davon nichts auf magnet-uri.sf.net? Der erste Link zeigt auf ein (veraltetes?) draft von 2002.
    private String magnet(DMetalink.FileEntry f)
    {
        
        String sha1 = null;
        if (f.hashes.containsKey("sha1")) 
        {
            sha1 = f.hashes.get("sha1");
            if ( sha1.length() == 40 )
            {
                sha1 = encodeSha1(sha1);
            }
            else
            {
                if ( sha1.length() != 32 ) {
                    sha1 = null;
                } 
            }
            
        }
        /* TODO: Check if the filename exists, just like we do with the sha1 */
        String dn = magnetify(f.filename);
        String magnet = "magnet:?" + (sha1 == null ? "" : "xt=urn:sha1:" + sha1 + "&") + "dn=" + dn;
        
        for ( DMetalink.UrlEntry u : f.urls )
        {
            if ( u.type.equals("http") )
            {
                magnet += "&as=" + magnetify(u.url);
            } 
        }
        return magnet;
    }
    
    private String magnetify ( String s )
    {
        return s.replaceAll(" ", "+").replaceAll("&", "&amp;");
    }
    
    /* can this be improved?? */
    private String encodeSha1 (String digest)
    {
        byte[] chars = new byte[20];
        for ( int i = 0; i < digest.length(); i+=2 )
        {
            int hn = Byte.parseByte (digest.substring(i, i+1), 16) << 4;
            int ln = Byte.parseByte (digest.substring(i+1, i+2), 16);
            int b = hn + ln;
            chars[i/2] = (new Integer(b)).byteValue();
        }
        return Base32.encode(chars);
    }
}
