// Copyright (C) 2007 Perdita Stevens

// UNDER DEVELOPMENT - aka UNFINISHED. However,

// This is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.

//package com.stevens_bradfield.game;
import javax.swing.*;
import javax.swing.border.Border;
import java.applet.AudioClip;
import java.awt.*;
import java.awt.event.*;
import java.util.*;

// Import the JLayer classes
import javazoom.jl.player.*;
	
import javax.sound.sampled.*;
import java.io.*;
import java.net.URL;

/**
 * @author perdita
 *
 */
public class Game extends JApplet implements ActionListener {
  private static int MAXMUSICS = 10;

  private int maximum;
  private boolean offerAddition;
  private boolean offerSubtraction;

  private JDialog settings;
  private JSlider maximumSlider;
  private JCheckBox additionBox;
  private JCheckBox subtractionBox;

  private String theSum;
  private String theAnswer;
  private int correctAnswer;
  private Music chosenSound;
  private Random r = new Random();
  private boolean addition;

  private JTextField t1, question, answer;
  private LinkedList<MyJButton> answerButtons;
  private LinkedList<MyJButton> musicButtons;
  private Border empty;

  public void init() {
    //get default parameter values
    try {
      maximum = Integer.parseInt(getParameter("maximum"));
    } catch (NumberFormatException nfe) {
      System.out.println("parameter maximum was invalid, defaulting to 9");
      maximum = 9;
    }
    String operators = getParameter("operators");
    offerAddition = operators.contains("+");
    offerSubtraction = operators.contains("-");

    //give the user the chance to change settings
    userSetup();
  }

  public void start() {
    //hmm, do we actually want to do anything at all here?
  }

  private void userSetup() {
    settings = new JDialog();
    settings.setSize(300,300); //think about this
    settings.setVisible(true);

    JPanel settingsPanel = new JPanel(new GridLayout(4,1));
    settings.add(settingsPanel);

    maximumSlider = new JSlider(JSlider.HORIZONTAL,
					0, 29, maximum);
    maximumSlider.setMajorTickSpacing(5);
    maximumSlider.setMinorTickSpacing(1);
    maximumSlider.setPaintTicks(true);
    maximumSlider.setPaintLabels(true);
    settingsPanel.add(maximumSlider, BorderLayout.NORTH);

    additionBox = new JCheckBox("+", offerAddition);
    additionBox.setMnemonic(KeyEvent.VK_P); 
    settingsPanel.add(additionBox);

    subtractionBox = new JCheckBox("-", offerSubtraction);
    subtractionBox.setMnemonic(KeyEvent.VK_S); 
    settingsPanel.add(subtractionBox);

    JButton ok = new JButton("OK");
    ok.setActionCommand("OK");
    ok.addActionListener(this);
    settingsPanel.add(ok, BorderLayout.SOUTH);

    settings.setVisible(true);
  }

  private void getUserSettings() {
    System.out.println("getUserSettings");
    maximum = maximumSlider.getValue();
    offerAddition = additionBox.isSelected();
    offerSubtraction = subtractionBox.isSelected();

    settings.dispose();

    //now set up the real screen
    addition = offerAddition; //start with an addition, if it's offered at all
    setupGui();
  }

  //answer must be between 0 and maximum (inclusive)
  private void setupSum() {
    int i = r.nextInt(maximum+1);
    if (addition) {
      int j = r.nextInt(maximum+1 - i);
      theSum = Integer.toString(i) + " + " + Integer.toString(j) + " = ";
      correctAnswer = i + j;
    } else { //subtraction
      int k = r.nextInt(i+1);
      theSum = Integer.toString(i) + " - " + Integer.toString(k) + " = ";
      correctAnswer = i - k;
    }
    question.setText(theSum);
    answer.setText("");
    setEnabledAnswerButtons(true);
  }

  private String[] getMusic() {
    String music = getParameter("music");
    if (music == null) {
      System.out.println("music parameter null");
      return null;
    }
    return music.split("\\s*,\\s*",MAXMUSICS);
  }

  private void setupGui() {
    System.out.println("setupGui");
    setLayout(new BorderLayout()); //necessary?
    JPanel musicPanel = new JPanel();
    //enough for 3 rows of buttons: otherwise, only the first gets space. 
    //Right way to get decent layout for any reasonable music collection?
    //Not GridLayout since want buttons to get natural width.
    musicPanel.setPreferredSize(new Dimension(0,160));

    musicButtons=new LinkedList<MyJButton>();
    String[] musics = getMusic();
    if (musics == null) {
      System.out.println ("No music found!");
    } else {
      for (int i=0; i < musics.length; i++) {
	String m = musics[i];
	String label = m;
	if (label.endsWith(".mp3")) {
	  label=label.substring(0,label.length()-4);
	} else {
	  System.out.println ("Couldn't parse "+label);
	}
	MyJButton b = new MyJButton(label);
	musicButtons.add(b);
	b.setActionCommand(m);
	b.addActionListener(this);
	musicPanel.add(b);
      }
    }

    //operator choice
    if (offerAddition && offerSubtraction) {
      JPanel operatorChoicePanel = new JPanel(new GridLayout(0,1));
      MyJButton plus = new MyJButton("+");
      MyJButton minus = new MyJButton("-");
      plus.setActionCommand("+");
      plus.addActionListener(this);
      minus.setActionCommand("-");
      minus.addActionListener(this);
      operatorChoicePanel.add(plus);
      operatorChoicePanel.add(minus);
      add(operatorChoicePanel, BorderLayout.WEST);
    }

    //the sum display
    question = new JTextField();
    answer = new JTextField();
    JPanel sumPanel = new JPanel(new GridLayout(1,2));
    sumPanel.add(question);
    sumPanel.add(answer);
    question.setEditable(false);
    answer.setEditable(false);
    question.setFont(new Font(null, Font.PLAIN, 50));
    answer.setFont(new Font(null, Font.PLAIN, 50));
    question.setHorizontalAlignment(JTextField.RIGHT);
    empty = BorderFactory.createEmptyBorder();
    question.setBorder(empty);
    answer.setBorder(empty);

    //answer buttons
    //bizarrely, JDK1.6 docs state that number of cols (10) only affects
    //layout when number of rows is 0!! So 0 it must be.
    JPanel answerButtonPanel = new JPanel(new GridLayout(0,10));
    answerButtons=new LinkedList<MyJButton>();
    for (int i = 0; i <= maximum; i++) {
      String iAsString = Integer.toString(i);
      MyJButton b = new MyJButton(iAsString);
      b.setActionCommand(iAsString);
      b.addActionListener(this);
      answerButtons.add(b);
      answerButtonPanel.add(b);
    }

    add(musicPanel, BorderLayout.NORTH);
    add(sumPanel, BorderLayout.CENTER);
    add(answerButtonPanel, BorderLayout.SOUTH);

    validate();
    setVisible(true);
  }

  public void actionPerformed(ActionEvent e) {
    String s = e.getActionCommand();
    // What is the right way to do this? It's horrible having this all in one method
    // if s is "OK", it's the settings
    // if s is a number, it's an answer, 
    // if it's +/- it's an operator change, 
    // otherwise it's a tune
    try{
      if (s=="OK") {getUserSettings();}
      else if (s=="+") {addition=true;}
      else if (s=="-") {addition=false;}
      else {
	int i = Integer.parseInt(s);
	if (checkAnswer(i)){
	  answer.setText(e.getActionCommand());
	  chosenSound.play(); //chosenSound will not be null!
	  setEnabledMusicButtons(true);
	  setEnabledAnswerButtons(false);
	} 
      }
    } catch (NumberFormatException nfe) {
      try {
	chosenSound = new Music(getCodeBase(), "Music/"+s);
      } catch (Exception ce) { 
	System.out.println (ce+" Failed to get music from "+s); 
	return;
      }
      setEnabledMusicButtons(false);
      setupSum();
    }
  }

  private void setEnabledAnswerButtons(boolean b) {
    for (MyJButton j : answerButtons)
      j.setEnabled(b);
  }

  private void setEnabledMusicButtons(boolean b) {
    for (MyJButton j : musicButtons)
      j.setEnabled(b);
  }

  public boolean checkAnswer (int ans){
    return (ans == correctAnswer);
  }

}


class MyJButton extends JButton {
  public MyJButton(String s) {
    super(s);
    setFont(new Font(null, Font.PLAIN, 30));
  }
}

class Music {
  private Player player;
  private InputStream is;

  URL url;

  public Music (URL codebase, String filename) {
    try {
      url = new URL(codebase.toString() + filename);
    } catch (Exception e) {
      System.out.println("failed to make URL, exception " + e.toString());
    } 
  }

  public void play() {
    try {
      InputStream is = url.openStream();
      player = new Player(is);
      MusicThread mt = new MusicThread();
      mt.start();
    } catch(Exception e) {
      e.printStackTrace();
    }
  }
 
  class MusicThread extends Thread
  {
    public void run()
    {
      try { 
	player.play();
      } catch( Exception e ) {
	e.printStackTrace();
      }
    }
  }
}


