package Cooperative;

import java.util.ArrayList;
import java.awt.event.ActionListener;
import java.awt.*;

import Common.PieChartFrame;

import javax.swing.*;

/**
 * Author: Max Buegler - max@sarstech.com
 * Date: Oct 14, 2009
 * Time: 11:39:44 PM
 */
public class ShapleyValue implements CoopAlgorithm{
    private boolean stop;

    private int factorial(int n){
        return factorial(1,n);
    }
    private int factorial(int n,int m){
        if(n==m)return n;
        return n*factorial(n+1,m);
    }
    private void getCoaltions(int p,int m, int n, ArrayList<Coalition> c, int[] cc){
        if (m==n)c.add(new Coalition(cc.clone(),0));
        else{
            for (int x=0;x<p;x++){
                boolean contain=false;
                for (int y=0;y<n;y++)if (cc[y]==x)contain=true;
                if (!contain){
                    cc[n]=x;
                    getCoaltions(p,m,n+1,c,cc);
                }
            }
        }
    }

    public void run(int p,ArrayList<Coalition> c, ActionListener finish) {
        stop=false;
        ArrayList<Coalition> c2=new ArrayList<Coalition>();
        getCoaltions(p,p,0,c2,new int[p]);
        double[] sums=new double[p];
        for (Coalition co:c2){
            if (stop)return;
            for (int x=0;x<p;x++){
                System.out.print((co.getPlayers()[x]+1));
                if (x<p-1)System.out.print(" - ");
            }
            System.out.print(" | ");
            for (int x=0;x<p;x++){
                double v=getCoalitionValue(c,co.getPlayers(),x);
                if ((int)v==v)System.out.print((int)v);
                else System.out.print(v);
                sums[x]+=v;
                if (x<p-1)System.out.print("  ");
            }
            System.out.println();
        }
        System.out.println("--------------------");
        for (int x=0;x<p;x++)
            System.out.print("__");
        System.out.print(" | ");
        for (int x=0;x<p;x++){
            if((int)sums[x]==sums[x])System.out.print((int)sums[x]+"  ");
            else System.out.print(sums[x]+"  ");
        }
        System.out.println();
        System.out.println();
        System.out.println("Payoffs: ");
        int fac=factorial(p);
        for (int x=0;x<p;x++){
            System.out.print("Player "+(x+1)+": ");
            if ((int)sums[x]==sums[x])System.out.print((int)sums[x]);
            else System.out.print(sums[x]);
            System.out.print("/"+fac+"  =  ");
            System.out.println(sums[x]/fac);
        }
        for (int x=0;x<sums.length;x++)sums[x]/=fac;
        new PieChartFrame("Shapley Value",sums);
        finish.actionPerformed(null);
    }
    private double getCoalitionValue(ArrayList<Coalition> c,int[] cc, int p){
        int pos=0;
        for (int x=0;x<cc.length;x++)if (cc[x]==p)pos=x;
        if (pos==0)return c.get(c.indexOf(new Coalition(new int[]{p},0))).getValue();
        int[] c1=new int[pos];
        for (int x=0;x<pos;x++){
            c1[x]=cc[x];
        }
        int[] c2=new int[pos+1];
        for (int x=0;x<pos+1;x++){
            c2[x]=cc[x];
        }
        return c.get(c.indexOf(new Coalition(c2,0))).getValue()-c.get(c.indexOf(new Coalition(c1,0))).getValue();
    }

    public void stop() {
        stop=true;
    }

    public void settings(ActionListener updater) {
        final JFrame settingsFrame=new JFrame("Dominated Actions settings");
        settingsFrame.setLayout(new GridBagLayout());
        GridBagConstraints cons=new GridBagConstraints();
        cons.weightx=0.5;
        cons.weighty=0.5;
        cons.gridx=0;
        cons.gridy=0;
        cons.gridheight=1;
        cons.gridwidth=1;
        cons.fill=GridBagConstraints.HORIZONTAL;
        JPanel aboutPanel=new JPanel();
        aboutPanel.setBorder(BorderFactory.createCompoundBorder(
                        BorderFactory.createTitledBorder("About"),
                        BorderFactory.createEmptyBorder(5,5,5,5)));
            aboutPanel.setLayout(new GridLayout(1,1));
            JTextArea about=new JTextArea();
            about.setEditable(false);
            about.setCursor(null);
            about.setOpaque(false);
            about.setFocusable(false);
            about.setLineWrap(true);
            about.setText("Calculates the Shapley value for the game");
            aboutPanel.add(about);
        settingsFrame.add(aboutPanel,cons);

        settingsFrame.setSize(300,200);
        settingsFrame.setVisible(true);
    }
    public String getDescriptor() {
        return "Shapley value";  //To change body of implemented methods use File | Settings | File Templates.
    }
}
