/*
 * ConventionalSolution.java
 *
 * Created on 7. unor 2006, 2:07
 *
 * To change this template, choose Tools | Options and locate the template under
 * the Source Creation and Management node. Right-click the template and choose
 * Open. You can then make changes to the template in the Source Editor.
 */

package cz.pcland.knapsack;

import cz.pcland.ga.*;
import cz.pcland.ga.fitness.Evaluator;
import cz.pcland.ga.fitness.PenalizationFitness;
import javax.swing.*;
import java.awt.*;
import cz.pcland.gavisualization.*;
import java.util.*;
import java.sql.Time;
import java.util.GregorianCalendar;
/**
 *
 * @author petr
 */
public class ConventionalSolution {
    JProgressBar pb;
    JLabel resultLabel;
    JList list;
    JLabel timeLabel;
    KnapSack ks;
    
    /** Creates a new instance of ConventionalSolution */
    public ConventionalSolution(JProgressBar pb, JLabel resultLabel, JList list, JLabel timeLabel, KnapSack ks) {
        this.pb = pb;
        this.ks = ks;
        this.resultLabel = resultLabel;
        this.list = list;
        this.timeLabel = timeLabel;
        
    }
    
    
    public void updateStatus(final double i, final String time) {
        Runnable doSetProgressBarValue = new Runnable() {
            public void run() {
                pb.setValue((int)i);
                timeLabel.setText(time);
            }
        };
        SwingUtilities.invokeLater(doSetProgressBarValue);
    }
    
    
    
    public void getApproximateSolution() {
        Vector itemsCopy = (Vector)ks.items.clone();
        Collections.sort(itemsCopy);
        list.setListData(itemsCopy);
        
        Vector tmp = new Vector();
        double sum = 0;
        double price = 0;
        double inSackSum = 0;
        int lastAdded = 0;
        for(int i = 0; i<itemsCopy.size();i++){
            sum+=((KnapSackItem)itemsCopy.get(i)).getCapacity();
            if(sum<=ks.getCapacity()){
                ((KnapSackItem)itemsCopy.get(i)).addToApproximate();
                tmp.add(0,itemsCopy.get(i));
                inSackSum += ((KnapSackItem)itemsCopy.get(i)).getCapacity();
                price += ((KnapSackItem)itemsCopy.get(i)).getPrice();
                lastAdded = i;
            }else {
                ((KnapSackItem)itemsCopy.get(i)).removeFromApproximate();
            }
        }
        
        if(lastAdded + 1 < itemsCopy.size()){
            for(int i = lastAdded + 1; i<itemsCopy.size();i++){
                if( (inSackSum + ((KnapSackItem)itemsCopy.get(i)).getCapacity()) <= ks.getCapacity()){
                    ((KnapSackItem)itemsCopy.get(i)).addToApproximate();
                    tmp.add(0,itemsCopy.get(i));
                    inSackSum += ((KnapSackItem)itemsCopy.get(i)).getCapacity();
                    price += ((KnapSackItem)itemsCopy.get(i)).getPrice();
                }
                    
            }
        }
        
        list.setListData(tmp);
        timeLabel.setText("done");
        resultLabel.setText(String.valueOf(price));
    }
    
    
    public void start(){
        
    }
    
    
    
    public Object doWork() {
        try {
            int totalItems = ks.totalItems();

            Evaluator fitness = new PenalizationFitness();
            fitness.setDataObject(ks);
            
            BinaryIndividual current = new BinaryIndividual(totalItems);
            
            boolean[] bits = new boolean[totalItems];
            for(int i=0;i<totalItems;i++) {
                bits[i] = false;
            }
            current.setString(bits);
            BinaryIndividual best = new BinaryIndividual(totalItems);
            best.setString(bits);
            best.setFitness(0);
            
            int j;
            boolean measureStart = true;
            //boolean measureStop = false;
            long startTime = 0;
            long endTime = 0;
            
            
            double possibilities = Math.pow(2,totalItems);

            for(double i = 0;i<possibilities;i++) {
                if(i%400000==0){
                    
                    if(measureStart){
                        startTime = System.currentTimeMillis();
                        measureStart = !measureStart;
                    }else{
                        endTime = System.currentTimeMillis();
                        updateStatus(i, Operations.getTime( ( (long)((endTime-startTime)*((possibilities-i)/400000) ))));
                        if (Thread.interrupted()) {
                            throw new InterruptedException();
                        }
                     
                        measureStart = !measureStart;
                    }
 
                    
                    
                }
                
                current.setFitness(fitness.getEvaluation(current));
                
                
                if(current.getFitness() > best.getFitness()){
                    best = new BinaryIndividual(current);
                }
                
                
                boolean[] currentBits = current.getString();
                for(j=totalItems-1;(j>=0);j--) if(!currentBits[j]) break; //find first zero bit of current individual
                if(j>=0){
                    currentBits[j]=true;
                    j++;
                    for(;j<totalItems;j++) {
                        currentBits[j]=false;
                    }
                }

            }
            
            resultLabel.setText(String.valueOf(best.getFitness()));
            
            final Vector tmp = new Vector();
            
            for(int i = 0; i<ks.items.size();i++){
                if(best.getString()[i]){
                    tmp.add(0,ks.items.get(i));
                }
            }
            //timeLabel.setText("done");
            
            Runnable setData = new Runnable() {
                public void run(){
                    list.setListData(tmp);
                }
            };
            SwingUtilities.invokeLater(setData);
            
            
        } catch (InterruptedException e) {
            updateStatus(0, "__");
            return "Interrupted";  // SwingWorker.get() returns this
        }
        return "All Done";         // or this
    }
}


