package Matrix2P;

import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.*;
import java.util.Random;

/**
 * Author: Max Buegler - max@sarstech.com
 * Date: Oct 5, 2009
 * Time: 8:52:28 PM
 */
public class MixedActionPlay implements GameAlgorithm{
    private int stepcount;
    private double[] p1,p2;
    private double epsilon;
    private boolean stop=false;
    private Random rnd;

    public String getDescriptor() {
        String out="Mixed Action Play [n="+stepcount+" p1=(";
        for (int x=0;x<p1.length;x++){
            out+=p1[x];
            if (x<p1.length-1)out+=",";
        }
        out+=")  p2=(";
        for (int x=0;x<p2.length;x++){
            out+=p2[x];
            if (x<p2.length-1)out+=",";
        }
        return out+") ]";
    }

    public void settings(ActionListener ul) {
        final ActionListener ul2=ul;
        final JFrame settingsFrame=new JFrame("Mixed action play 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("Performs a Fictitious Play where players play based on observations.");
                    aboutPanel.add(about);
                settingsFrame.add(aboutPanel,cons);

                JPanel settingsPanel=new JPanel();
                    settingsPanel.setLayout(new GridLayout(5,2));
                    settingsPanel.add(new JLabel("Pl 1 strategy ','-separated"));
                    String s1="";
                    for (int x=0;x<p1.length;x++){
                        s1+=p1[x];
                        if (x<p1.length-1)s1+=",";
                    }
                    final JTextField a1=new JTextField(s1+"");
                    settingsPanel.add(a1);
                    settingsPanel.add(new JLabel("Pl 2 strategy ','-separated"));
                    String s2="";
                    for (int x=0;x<p2.length;x++){
                        s2+=p2[x];
                        if (x<p2.length-1)s2+=",";
                    }
                    final JTextField a2=new JTextField(s2+"");
                    settingsPanel.add(a2);
                    settingsPanel.add(new JLabel("Epsilon for sampler"));
                    final JTextField ep=new JTextField(epsilon+"");
                    settingsPanel.add(ep);
                    settingsPanel.add(new JLabel("Number of games"));
                    final JTextField g=new JTextField(stepcount+"");
                    settingsPanel.add(g);

                    JPanel button1=new JPanel();
                        button1.setLayout(new GridLayout(1,2));
                        JButton ok=new JButton("OK");
                        ok.addActionListener(new ActionListener(){
                            public void actionPerformed(ActionEvent e) {
                                int vals=1;
                                String t=a1.getText();
                                for (int x=0;x<t.length();x++)if (t.charAt(x)==',')vals++;
                                double[] v1=new double[vals];
                                double sum=0;
                                for (int x=0;x<vals;x++){
                                    int i=t.indexOf(',');
                                    if (i>0){
                                        try{
                                            v1[x]=Double.parseDouble(t.substring(0,i));
                                            if (v1[x]<0)throw new Exception();
                                        }catch(Exception ex){
                                            JOptionPane.showMessageDialog(settingsFrame,"Please enter a series of ','-separated positive real values for 'Pl 1 strategy'");
                                            return;
                                        }
                                        t=t.substring(i+1);
                                    }
                                    if (i<=0){
                                        try{
                                            v1[x]=Double.parseDouble(t);
                                            if (v1[x]<0)throw new Exception();
                                        }catch(Exception ex){
                                            JOptionPane.showMessageDialog(settingsFrame,"Please enter a series of ','-separated positive real values for 'Pl 1 strategy'");
                                            return;
                                        }

                                    }
                                    sum+=v1[x];
                                }
                                for (int x=0;x<vals;x++)v1[x]/=sum;
                                p1=v1;


                                vals=1;
                                t=a2.getText();
                                for (int x=0;x<t.length();x++)if (t.charAt(x)==',')vals++;
                                double[] v2=new double[vals];
                                sum=0;
                                for (int x=0;x<vals;x++){
                                    int i=t.indexOf(',');
                                    if (i>0){
                                        try{
                                            v2[x]=Double.parseDouble(t.substring(0,i));
                                            if (v2[x]<0)throw new Exception();
                                        }catch(Exception ex){
                                            JOptionPane.showMessageDialog(settingsFrame,"Please enter a series of ','-separated positive real values for 'Pl 2 strategy'");
                                            return;
                                        }
                                        t=t.substring(i+1);
                                    }
                                    if (i<=0){
                                        try{
                                            v2[x]=Double.parseDouble(t);
                                            if (v2[x]<0)throw new Exception();
                                        }catch(Exception ex){
                                            JOptionPane.showMessageDialog(settingsFrame,"Please enter a series of ','-separated positive real values for 'Pl 2 strategy'");
                                            return;
                                        }

                                    }
                                    sum+=v2[x];
                                }
                                for (int x=0;x<vals;x++)v2[x]/=sum;
                                p2=v2;

                                try{
                                    epsilon=Double.parseDouble(ep.getText());
                                    if (epsilon<0||epsilon>1)throw new Exception();
                                }catch(Exception ex){
                                    JOptionPane.showMessageDialog(settingsFrame,"Please enter a positive real value between 0 and 1 for 'Epsilon for sampler'");
                                    return;
                                }
                                try{
                                    stepcount=Integer.parseInt(g.getText());
                                }catch(Exception ex){
                                    JOptionPane.showMessageDialog(settingsFrame,"Please enter a positive integer value for 'Number of games'");
                                    return;
                                }
                                ul2.actionPerformed(null);
                                settingsFrame.setVisible(false);
                            }
                        });
                        button1.add(new JLabel());
                        button1.add(ok);
                        settingsPanel.add(button1);
                    JPanel button2=new JPanel();
                        button2.setLayout(new GridLayout(1,2));
                        JButton cancel=new JButton("Cancel");
                        cancel.addActionListener(new ActionListener(){
                            public void actionPerformed(ActionEvent e) {
                                settingsFrame.setVisible(false);
                            }
                        });
                        button2.add(cancel);
                        button2.add(new JLabel());
                        settingsPanel.add(button2);
                cons=new GridBagConstraints();
                cons.weightx=0.5;
                cons.weighty=0.5;
                cons.gridx=0;
                cons.gridy=1;
                cons.gridheight=3;
                cons.gridwidth=1;
                cons.fill=GridBagConstraints.HORIZONTAL;
                settingsFrame.add(settingsPanel,cons);



                settingsFrame.setSize(400,400);
                settingsFrame.setVisible(true);

    }

    public MixedActionPlay() {
        rnd=new Random();
        p1=new double[]{};
        p2=new double[]{};
        stepcount=1000;
    }

    public void run(GameMatrix m, ActionListener finish) {
        stop=false;
        double po1=0,po2=0;
        for (int x=0;x<stepcount;x++){
            if (stop){
                finish.actionPerformed(null);
                return;
            }
            int a1=sample(p1,epsilon);
            int a2=sample(p2,epsilon);
            po1+=m.getP1()[a1][a2];
            po2+=m.getP2()[a1][a2];
            System.out.println("Step "+(x+1)+" : P1 plays: "+(a1+1)+"  P2 plays: "+(a2+1));
            System.out.println("   P1 payoff: "+po1+"  P2 payoff: "+po2);
            System.out.println("   P1 avg. payoff: "+(po1/(x+1))+"  P2 avg. payoff: "+(po2/(x+1)));
        }
        finish.actionPerformed(null);        
    }

    public void stop() {
        stop=true;
    }

    private int sample(double[] p, double e){
        double[] cum=new double[p.length];
        double sum=0;
        double v=rnd.nextDouble();
        if (v<e)return rnd.nextInt(p.length);
        v=rnd.nextDouble();
        for (int x=0;x<p.length;x++){
            sum+=p[x];
            cum[x]=sum;
            double ll=-1;
            if (x>0)ll=cum[x-1];
            if (v>ll&&v<=sum)return x;
        }
        return 0;
    }


}
