package lt.ktu.gmj.tasks;

import javax.swing.JOptionPane;

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.Random;
import java.util.StringTokenizer;
import lt.ktu.HostNameRetriever;
import lt.ktu.gmj.*;
import lt.ktu.gmj.propertySheet.*;

// Referenced classes of package lt.ktu.gmj.tasks:
//            KnapSackDomain, KnapWeightProvider, KnapDataUrlProvider

public class Knapsack
    implements Task
{

    private double total_weight;
    
    ArrayList<Item>	items;
    
    private Random rnd;
    private String data_url;
    private String data_url_old;
    private KnapSackDomain mydomain;

    public static double MinWeight = 0;
    public static double MaxWeight = 1000000;
    
    public double Capacity()
    {
    	return total_weight;
    }
    public void Capacity(double value)
    {
    	total_weight = value;
    }
    public String DataUrl()
    {
    	return data_url;
    }
    public void DataUrl(String value)
    {
    	data_url = value;
    }
    private void input()
    	throws MalformedURLException, IOException
    {
    	if(items == null)
		items = new ArrayList<Item>();
	URL url = new URL(data_url);
	URLConnection con = url.openConnection();
	InputStream srInput = con.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(srInput));
	reader.readLine();	//skip headers
	String line;
	float weight, price;
	int amount;
	String name;
	while( (line = reader.readLine()) != null )
	{
		StringTokenizer st = new StringTokenizer(line);
		weight = Float.valueOf(st.nextToken()).floatValue();
		price = Float.valueOf(st.nextToken()).floatValue();
		amount = Integer.valueOf(st.nextToken()).intValue();
		name = st.nextToken();
		items.add(new Item(weight, price, amount, name));
	}
	reader.close();
	srInput.close();
    }
    
    /*
    	kiekviena p reiksme padalina is bendros sumos: a(i) = a(i) / sum(a) 
    */
    private void normalize(Point p)
    {
	double sum = 0;
	for ( double x : p.x )
		sum += x;
	for( int i = 0 ; i < p.x.length ; i++ )
		p.x[i] /= sum;
    }

    private IResult calculate(Point p)
    {
    	double weight = 0.0D;
	double cost = 0.0D;
	double hsum = 0.0D;
	Item max;
	
	KnapsackResult	res = new KnapsackResult();
	
	max = items.get(0);
	for ( Item i : items )
		i.taken(false);
	for ( int n = items.size() ; n >= 0 ; n-- )
	{
		hsum = 0.0D;
		for ( Item item : items )
			if ( !item.taken() ) {
				if( max.ratio() < item.ratio() ) max = item;
				hsum += item.ratio();
			}
		hsum = 1.0D / hsum;
		double eps = rnd.nextDouble();
		double r = 0.0D;
		for ( Item item : items ) {
			if( !item.taken() ) {
				r += (1.0D / (double)n) * p.x[0] + 
					hsum * p.x[1] * item.ratio() +
					p.x[2] * (double)(item != max ? 0 : 1);
				if( r <= eps ) continue;
				if( weight + item.weight()> total_weight ) {
					// pakeitimas
					continue; // jei butu perpildymas, tai renkames kita o ne baigiame.
					//pakeitimas
					//res.value(-cost);
					//System.out.println("Total cost:" + res.totalCost() + " total weight:" + res.totalWeight());
					//System.out.println("--------------------");
					//return res;
				}
				weight += item.weight();
				cost += item.price();
				item.taken(true);
				//System.out.println("Add: " + item.name() + " cost:" + item.price() + " weight:" + item.weight());
				res.add(item);
				break;
			}
		}
	}
	//return -cost;
	// gmj skirtas minimizuoti, mum reikia maximizuoti
	res.value(-cost);
	/*
	System.out.println("Total cost:" + res.totalCost() + " total weight:" + res.totalWeight());
	System.out.println("--------------------");
	*/
	return res;
    }
    
    public Domain domain()
    {
        return mydomain;
    }

    public Knapsack()
    {
        total_weight = 10D;
        rnd = new Random();
        data_url_old = new String();
        mydomain = new KnapSackDomain();
        data_url = HostNameRetriever.getCodeBase() + "norveda.txt";
    }

    public void customize(PropertyManager manager)
    {
        manager.add(new DoubleProperty("Total Weight", new KnapWeightProvider(this), this.MinWeight, this.MaxWeight));
        manager.add(new UrlProperty("URL of data file", new KnapDataUrlProvider(this)));
    }

    public IResult f(Point pt)
    {
        normalize(pt);
        if(!data_url.equals(data_url_old))
            try
            {
                input();
                data_url_old = new String(data_url);
            }
            catch(Exception e)
            {
                System.out.println("Error reading from data file: " + e);
		JOptionPane.showMessageDialog(null, e, "While reading input", JOptionPane.INFORMATION_MESSAGE);
            }
        return calculate(pt);
    }
}
