package phex.tools;

import java.io.*;
import java.net.*;
import java.util.*;

import phex.host.HostAddress;

/**
 * 
 */
public class Ip2CountryDBBuilder
{
    //ftp://ftp.apnic.net/pub/stats/<registry>/delegated-<registry>-latest
    private static final String APNIC = "ftp://ftp.apnic.net/pub/stats/apnic/delegated-apnic-latest";
    private static final String RIPE = "ftp://ftp.apnic.net/pub/stats/ripe-ncc/delegated-ripencc-latest";
    private static final String ARIN = "ftp://ftp.apnic.net/pub/stats/arin/delegated-arin-latest";
    private static final String LACNIC = "ftp://ftp.apnic.net/pub/stats/lacnic/delegated-lacnic-latest";
    
    private static List dataList;
    
    public static void main( String args[] )
        throws Exception
    {
        dataList = new ArrayList();
        
        String[] rirs = {LACNIC, APNIC, RIPE, ARIN };
        for ( int i = 0; i < rirs.length; i++ )
        {
            System.out.println( "Loading " + rirs[i] );
            URL url = new URL( rirs[i] );
            URLConnection connection = url.openConnection();
            InputStream inputStream = connection.getInputStream();
            readData(inputStream);
            System.out.println( "Total data read: " + dataList.size() );
            inputStream.close();
        }
        
        Collections.sort( dataList );
        
        //writeToOutputFile( "full.csv" );
        
        System.out.println( "before size: " + dataList.size() );
        consolidateList();
        System.out.println( "after size: " + dataList.size() );
        
        writeToOutputFile( "ip2country.csv" );
    }

    private static void writeToOutputFile( String fileName ) throws IOException
    {
        // write to output file
        BufferedWriter writer = new BufferedWriter( new FileWriter( "src/phex/resources/" + fileName ) );
        Iterator iterator = dataList.iterator();
        while ( iterator.hasNext() )
        {
            IpCountryRange range = (IpCountryRange)iterator.next();
            //writer.write( "\"" + range.from + "\",\"" + range.to + "\",\""
            //    + range.countryCode + "\"\n" );
            writer.write( "" + range.from + "," + range.to + ","
                + range.countryCode + "\n" );
        }
        writer.close();
    }
    
    private static void consolidateList()
    {
        List consolidatedList = new ArrayList();
        int size = dataList.size();
        for ( int i = 0; i < size; i++ )
        {
            IpCountryRange range = (IpCountryRange)dataList.get( i );
//System.out.println( "range: " + range );            
            for ( int j = i+1; j < size; j++ )
            {
                IpCountryRange nextRange = (IpCountryRange)dataList.get( j );
//System.out.println( "nextrange: " + nextRange );
                if ( !range.countryCode.equals( nextRange.countryCode ) )
                {
                    break;
                }
                if ( range.to + 1 != nextRange.from )
                {
                    break;
                }
                // expand range
                range.to = range.to + nextRange.to - nextRange.from + 1;
//System.out.println( "newrange: " + range );
                // skip item..
                i++;
            }
            consolidatedList.add( range );
        }
        dataList = consolidatedList;
    }

    private static void readData(InputStream inputStream) throws IOException
    {
        BufferedReader reader = new BufferedReader( new InputStreamReader(
            inputStream ) );
        String line;
        while ( (line = reader.readLine()) != null )
        {
            if ( line.startsWith( "#" ) )
            {// comment
                continue;
            }
            if ( line.startsWith( "2") )
            {// version
                continue;
            }
            if ( line.endsWith( "summary") )
            {// summary line
                continue;
            }
            // record!
            StringTokenizer tokenizer = new StringTokenizer( line, "|" );
            // registry
            tokenizer.nextToken();
            // country
            String countryCode = tokenizer.nextToken();
            // type 
            String type = tokenizer.nextToken();
            if ( !type.equals( "ipv4" ) )
            {
                continue;
            }
            // start
            String start = tokenizer.nextToken();
            // value 
            String value = tokenizer.nextToken();
            long rangeValue = Long.parseLong( value );
            
            byte[] ip = HostAddress.parseIP( start );
            int v1 =  ip[3]        & 0xFF;
            int v2 = (ip[2] <<  8) & 0xFF00;
            int v3 = (ip[1] << 16) & 0xFF0000;
            int v4 = (ip[0] << 24);
            long ipValue = ((long)(v4|v3|v2|v1)) & 0x00000000FFFFFFFFl;
            long toIpValue = ipValue + rangeValue - 1;
            
            IpCountryRange range = new IpCountryRange( ipValue, toIpValue, countryCode );
            dataList.add( range );
            //System.out.println( start + " " + ipValue + " " + value );
        }
    }
    
    private static class IpCountryRange implements Comparable
    {
        long from;
        long to;
        String countryCode;
        
        public IpCountryRange( long from, long to, String cc )
        {
            this.from = from;
            this.to = to;
            countryCode = cc;
        }
        
        public String toString()
        {
            return String.valueOf( from ) + " - " + String.valueOf( to ) + " " + countryCode; 
        }

        public int compareTo(Object o)
        {
            IpCountryRange range = (IpCountryRange)o;
            if ( from > range.from )
            {
                return 1;
            }
            else if ( from < range.from )
            {
                return -1;
            }
            return 0;
        }        
    }
}
