
/**
 * PlayFrame.java
 *
 *
 * Created: Wed Jul 16 09:20:37 2003
 *
 * @author <a href="mailto: jan@newmarch.name">jan newmarch</a>
 * @version
 */

package client;

import common.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import net.jini.core.event.RemoteEvent;
import java.rmi.Remote;
import net.jini.core.event.RemoteEventListener;
import java.rmi.MarshalledObject;
import java.io.IOException;
import java.rmi.RemoteException;
import javax.swing.event.*;

import net.jini.core.lookup.ServiceItem;

public class PlayFrame extends JFrame implements ActionListener,
						 ChangeListener,
						 RemoteEventListener {
    private ServiceItem[] sources;
    private ServiceItem sinkItem;
    private Sink sink;
    private Source source;

    private JList sourceList = new JList();
    private JButton stopBtn = new JButton("Stop");
    private JLabel sinkLabel = new JLabel();
    private JSlider sourceVolumeCtl = new JSlider();
    private JSlider sinkVolumeCtl = new JSlider();

    private DefaultListModel  model;
    private Remote proxy;
    private GUIClient client;

    public PlayFrame(GUIClient client) {
	setTitle("Player");
	this.client = client;

	JPanel bottomPanel = new JPanel();
	bottomPanel.setLayout(new BorderLayout());
	Container contentPane = getContentPane();
	contentPane.setLayout(new BorderLayout());
	contentPane.add(sinkLabel, BorderLayout.NORTH);
	contentPane.add(sourceList, BorderLayout.CENTER);
	contentPane.add(bottomPanel, BorderLayout.SOUTH);

	JPanel volumeControls = new JPanel();
	volumeControls.setLayout(new GridLayout(1, 2));
	volumeControls.add(sourceVolumeCtl);
	volumeControls.add(sinkVolumeCtl);

	JPanel buttons = new JPanel();
	buttons.setLayout(new GridLayout(1,3));
	buttons.add(stopBtn);

	bottomPanel.add(volumeControls, BorderLayout.NORTH);
	bottomPanel.add(buttons, BorderLayout.SOUTH);

	stopBtn.addActionListener(this);

	LabelCellRenderer labelRend = new LabelCellRenderer();
    
	sourceList.setCellRenderer(labelRend);
	model = new DefaultListModel();
	sourceList.setModel(model);

	sourceVolumeCtl.setEnabled(false);
	sinkVolumeCtl.setEnabled(false);
	sourceVolumeCtl.addChangeListener(this);
	sinkVolumeCtl.addChangeListener(this);
	sourceVolumeCtl.setToolTipText("Set volume on the source");
	sinkVolumeCtl.setToolTipText("Set volume on the sink");

	setSize(400, 300);
	setVisible(true);
    }

    public void actionPerformed(ActionEvent evt) {
	if (evt.getSource() == stopBtn) {
	    try {
		sink.stop();
		sinkVolumeCtl.setEnabled(false);
		sourceVolumeCtl.setEnabled(false);
	    } catch(RemoteException e) {
		e.printStackTrace();
	    } catch(NotRecordingException e) {
		e.printStackTrace();
	    }
	}
    }

    public void stateChanged(ChangeEvent e) {
	JSlider slider = (JSlider) e.getSource();
	int vol = slider.getValue();
	VolumeControl volCtl = null;
	if (slider == sinkVolumeCtl) {
	    volCtl = (VolumeControl) sink;
	} else if (slider == sourceVolumeCtl) {
	    volCtl = (VolumeControl) source;
	}
	try {
	    volCtl.setVolume(vol);
	} catch(RemoteException ex) {
	    // ignore
	}
    }

    public void play(ServiceItem[] sources, ServiceItem sinkItem) {
	if ((sources == null) || (sources.length == 0)) {
	    System.out.println("Play: null sources");
	    dispose();
	    return;
	}

	this.sources = sources;
	this.sinkItem = sinkItem;
	sink = (Sink) sinkItem.service;
	source = (Source) sources[0].service;

	sinkLabel.setText("Playing to " + sinkItem.toString());

	model.clear();
	for (int n = 0; n < sources.length; n++) {
	    model.addElement(sources[n]);
	}

	ServiceItem[] rest = new ServiceItem[sources.length - 1];
	for (int n = 0; n < rest.length; n++) {
	    rest[n] = sources[n + 1];
	}
	MarshalledObject handback = null;
	try {
	    handback = new MarshalledObject(new SourceSink(rest, sinkItem));
	} catch(java.io.IOException e) {
	    e.printStackTrace();
	    return;
	}

	try {
	    if (proxy == null) {
		proxy = client.export(this);
	    }
	    // source.addSourceListener((RemoteEventListener) proxy, null);
	    System.out.println("Added source " + source + " proxy " + proxy);
	    sink.addSinkListener((RemoteEventListener) proxy, handback);
	    System.out.println("Added sink " + sink + " proxy " + proxy + " handback " + 
			       ((SourceSink) handback.get()).sources);
	} catch(RemoteException e) {
	    e.printStackTrace();
	} catch(Exception e) {
	    e.printStackTrace();
	}

	try{
	    System.out.println("Setting sink to: " + sink);
	    source.addSink(sink);
	    System.out.println("Setting source to: " + source);
	    sink.addSource(source);
	    System.out.println("Playing" + sources[0].attributeSets[0]);
	    source.play();
	    sink.record();
	} catch(AlreadyPlayingException e) {
	    JOptionPane.showMessageDialog(null,
					  "Source already playing",
					  "Play error",
					  JOptionPane.ERROR_MESSAGE);
	    return;
	} catch(AlreadyRecordingException e) {
	    JOptionPane.showMessageDialog(null,
					  "Sink already recording",
					  "Record error",
					  JOptionPane.ERROR_MESSAGE);
	    return;
	} catch(Exception e) {
	    // IncompatableSink/Source
	    e.printStackTrace();
	    return;
	}

	System.out.println("Checking VC " + sink);

	if (source instanceof VolumeControl) {
	    System.out.println("Source is VC");
	    enableVolumeControl( (VolumeControl) source, sourceVolumeCtl);
	}
	if (sink instanceof VolumeControl) {
	    System.out.println("Sink is VC");
	    enableVolumeControl( (VolumeControl) sink, sinkVolumeCtl);
	}
    }

    public void notify(RemoteEvent evt) {
	Object src = evt.getSource();
	System.out.println("Updating " + src);
	if ((src instanceof Sink) && 
	    (evt.getID() == Sink.STOP)) {
	    System.out.println("Sink stopped event");
	    Sink sink = (Sink) src;

	    try {
		sink.removeSinkListener((RemoteEventListener) proxy);
	    } catch(RemoteException e) {
		// ignore
	    }

	    MarshalledObject handback = evt.getRegistrationObject();
	    SourceSink ss = null;
	    try {
		ss = (SourceSink) handback.get();
	    } catch(Exception e) {
		e.printStackTrace();
		return;
	    }

	    ServiceItem[] sources = ss.sources;
	    ServiceItem sinkItem = ss.sink;
	    System.out.println("  stop -> play: sources " + sources + " sink " + sink);
	    play(sources, sinkItem);

	} else if ((src instanceof Source) && 
	    (evt.getID() == Source.STOP)) {
	    System.out.println("Source stopped event");
	}
    }

    private void enableVolumeControl(VolumeControl vol, JSlider slider) {
	int maxVol = 0;
	int currVol = 0;
	try {
	    maxVol = vol.getMaxVolume();
	    if (maxVol <= 0) return;

	    currVol = vol.getVolume();
	    System.out.println("Current vol: " + currVol);
	    if (currVol < 0 || currVol > maxVol) return;
	} catch (RemoteException e) {
	    e.printStackTrace();
	    return;
	}
	slider.setMinimum(0);
	slider.setMaximum(maxVol);
	slider.setValue(currVol);
	slider.setEnabled(true);
    }
}// PlayFrame
